0

大家好,我是 Java 新手,我正在 Uni 上一门课程。我的任务是编写一个小游戏,该游戏会生成玩家会猜到的随机 nr。在猜测玩家应该可以选择再次播放或等待并自动返回主菜单。

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

唯一的问题是当我从我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();

    }

}
4

2 回答 2

0

只解决您眼前的问题:

您的 run 方法需要设置y为 1 以外的值(可能为 0),然后调用interruptY/N 线程。这将使用 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 需要知道包含tryAgain在“tryAgainThread”中运行的调用的类的相关(可能是唯一的)实例。在您的情况下,一些静态公共字段可以完成这项工作,但理想情况下您会想要更优雅的东西。

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

于 2013-10-17T15:39:30.610 回答
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;
    }
}

ExecutorService接下来,我们使用 the和Futurefromjava.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(...)等待 5 秒以获得有效应答。如果 没有返回有效答案OurNonBlockingConsoleReader.callFuture.get则会引发TimeoutException.

于 2013-10-17T12:49:27.907 回答