如何在使用timertask并调用new方法后杀掉旧线程?

时间:2013-10-17 11:08:39

标签: java multithreading

大家好,我是Java的新手,我在大学学习一门课程。我已经完成了编写一个小游戏的任务,该游戏会生成玩家猜测的随机数。猜测玩家应该再次选择游戏或等待并自动返回主菜单。

首先我尝试thread.sleep(5000),但它因为等待用户输入(nextLine)而卡住了。然后一个朋友告诉我关于计时器和timertask,我用过,现在我的游戏几乎正常工作。

唯一的问题是当我从我的run()方法调用一个新方法时,后台运行的旧(再次播放Y / N)线程没有结束。因此,当我的菜单在5秒后出现时,我的第一个输入再次连接到播放Y / N选项而不是主菜单选项。以下是kod部分:

public void tryAgain() {
    Timer timer = new Timer();
    Task timerTask = new Task();
    int y = 1;
    String yesNo = sc.nextLine();
    System.out.println("Try again Y/N");
    Statistics.setGames(games);
    timer.schedule(timerTask, 5000);

    do {
        try {

            yesNo = sc.nextLine();
            if (yesNo.equals("Y") || yesNo.equals("y")) {
                guesses = 0;
                y = 2;
                timerTask.cancel();
                playGame();


            } else if (yesNo.equals("N") || yesNo.equals("n")) {
                y = 3;
                timerTask.cancel();
                Statistics.setGames(games);
                menu.showMainMenu();

            } else {
                System.out.println("Wrong input, try Y or N:");

            }

        } catch (Exception e) {
            sc.next();

            System.out.println("Wrong input, try Y or N:");

        }

    } while (y == 1);

}

和:

import java.util.TimerTask;

class Task extends TimerTask {

    play menu = new play();

    public void run() {

        Statistics.getGames();

        menu.menu.showMainMenu();

        cancel();

    }

}

2 个答案:

答案 0 :(得分:0)

您无法中断阻止读取。但您可以使用BufferedReader.ready()方法,它将告诉我们是否可以读取基础流。

让我们实现一个非阻塞读者:

public class OurNonBlockingConsoleReader implements Callable<String> {

    public String call() throws IOException {
        BufferedReader sysInReader = new BufferedReader(new InputStreamReader(System.in));
        String answer;
        do {
            System.out.println("Try again Y/N");
            try {
                while (!sysInReader.ready()) {
                    Thread.sleep(100);
                }
                answer = sysInReader.readLine();
            } catch (InterruptedException e) {
                return null;
            }
        } while (!"y".equalsIgnoreCase(answer) && !"n".equalsIgnoreCase(answer));
        return answer;
    }
}

接下来,我们使用ExecutorServiceFuture java.util.concurrent包中的public void tryAgain() throws InterruptedException, ExecutionException { ExecutorService readerExecutor = Executors.newSingleThreadExecutor(); Future<String> readerResult = readerExecutor.submit(new OurNonBlockingConsoleReader()); try { String answer = readerResult.get(5, TimeUnit.SECONDS); if ("y".equalsIgnoreCase(answer)) { playTheGame(); } else { goToMainTheMenu(); } } catch (TimeoutException e) { goToMainTheMenu(); } finally { readerExecutor.shutdownNow(); } } 来暂停调用此阅读器:

readerResult.get(...)

OurNonBlockingConsoleReader.call来电将等待5秒钟以获得有效答案。从Future.get返回的有效答案无效,TimeoutException会提出{{1}}。

答案 1 :(得分:0)

仅解决您的直接问题:

您的run方法需要将y设置为1以外的值(可能为0),然后在Y / N线程上调用interrupt。这将使用InterruptException或ClosedByInterruptException来阻止读取。 (您的catch块需要更智能。)然后Y / N循环将结束,因为y不是1.问题结束。

要使其正常工作,需要将y声明为volatile,或者每个 使用自己的副本。 (仅在同步块内访问它也可以。)

添加了示例:

public class YesNo  {
    private volatile Thread  tryAgainThread;
    private volatile int     y = 1;

    public doNotTryAgain()  {
        y = 0;
        tryAgainThread.interrupt();
    }
    //  Called only from tryAgainThread thread.
    public void tryAgain()  {
        do  {
            try {
                // Exactly what you have now.
                ...
            }
            catch (Exception e)  {}
        }  while (y == 1);
    }
....

class Task extends TimerTask  {
    public YesNo  ynInstance;
    ...
    public void run()  {
        ynInstance.doNotTryAgain();
        Statistics.getGames();
        ...
    }
}

我会让你弄清楚如何设置tryAgainThread,这是调用tryAgain方法的线程 - 并且正在循环开启。此外,Task需要知道包含在'tryAgainThread'中运行的tryAgain调用的类的相关(可能是唯一的)实例。在你的情况下,一些静态公共字段将完成这项工作,但理想情况下你想要更优雅的东西。

此外,catch (Exception e) {}可以正常使用,但理想情况下,您可以更好地检查您的例外情况。