大家好,我是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();
}
}
答案 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;
}
}
接下来,我们使用ExecutorService
和Future
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) {}
可以正常使用,但理想情况下,您可以更好地检查您的例外情况。