Java控制台版Hangman游戏超时功能异常问题求助
解决Hangman游戏超时后循环不终止的问题
问题根源
- Scanner阻塞:
scanner.nextLine()是阻塞方法,主线程会一直停在这里等待用户输入,即使20秒超时后timeout变为true,也无法进入循环条件判断或执行break语句。 - 内存可见性:
timeout变量未用volatile修饰,TimerTask线程修改该变量后,主线程可能无法立即看到更新后的取值,导致循环条件判断失效。
解决方案
步骤1:修复内存可见性
给timeout变量添加volatile关键字,确保多线程间的变量可见性:
private static volatile boolean timeout;
步骤2:替换阻塞式输入为带超时的非阻塞读取
使用ExecutorService配合Future实现带超时的输入读取,替代原有的scanner.nextLine(),超时后直接终止输入等待。
修改main方法中的输入读取部分,替换原有的char letter = scanner.nextLine().charAt(0);代码块:
// 计算剩余时间 long remainingTime = (20 * 1000) - (System.currentTimeMillis() - startTime); if (remainingTime <= 0) { timeout = true; break; } // 带超时的输入读取 ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(() -> scanner.nextLine()); String input = null; try { input = future.get(remainingTime, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { timeout = true; future.cancel(true); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } executor.shutdown(); if (timeout || input == null || input.isEmpty()) { continue; } char letter = input.charAt(0);
完整修改后的关键代码片段
public static void main(String[] args) throws IOException { scanner = new Scanner(System.in); // 原有分类选择代码保持不变 int n = (int) Math.floor(Math.random() * (5)) + 1; String word = null; switch (n) { case 1: System.out.println(ANSI_GREEN + "Category: fruits" + ANSI_RESET); word = fruits[(int) (Math.random() * fruits.length)]; break; case 2: System.out.println(ANSI_GREEN + "Category: countries" + ANSI_RESET); word = countries[(int) (Math.random() * countries.length)]; break; case 3: System.out.println(ANSI_GREEN + "Category: animals" + ANSI_RESET); word = animals[(int) (Math.random() * animals.length)]; // 修正原错误的length引用 break; case 4: System.out.println(ANSI_GREEN + "Category: languages" + ANSI_RESET); word = languages[(int) (Math.random() * languages.length)]; // 修正原错误的length引用 break; case 5: System.out.println(ANSI_GREEN + "Category: occupations" + ANSI_RESET); word = occupations[(int) (Math.random() * occupations.length)]; // 修正原错误的length引用 break; } timeout = false; Timer timer = new Timer(); long startTime = System.currentTimeMillis(); timer.schedule(new TimerTask() { public void run() { timeout = true; } }, 20 * 1000); // 原有字符数组初始化代码保持不变 int nb = word.length(); String chl = word; char[] ch = new char[nb]; String chf = ""; for (int i = 0; i < nb; i++) { ch[i] = '-'; chf += '*'; } System.out.println(ANSI_BLUE + "Word contains " + nb + " letters: " + ANSI_RESET); System.out.println(ANSI_RED + "You have 20 secs. Go!" + ANSI_RESET); int tries = 0; while (!timeout && tries < 7 && !word.equals(chf)) { System.out.println("Current progress: " + new String(ch)); if (timeout) { break; } System.out.print(ANSI_RED + "\nGuess a letter: " + ANSI_RESET); // 带超时的输入读取逻辑 long remainingTime = (20 * 1000) - (System.currentTimeMillis() - startTime); if (remainingTime <= 0) { timeout = true; break; } ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(() -> scanner.nextLine()); String input = null; try { input = future.get(remainingTime, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { timeout = true; future.cancel(true); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } executor.shutdown(); if (timeout || input == null || input.isEmpty()) { continue; } char letter = input.charAt(0); System.out.println("Time left: " + remainingTime / 1000 + " seconds"); int pos = word.indexOf(letter); if (pos == -1) { System.out.println("\nWrong Guess!"); tries++; hangman(tries, chl); } else { while (pos != -1) { ch[pos] = letter; word = word.replaceFirst(String.valueOf(letter), "*"); pos = word.indexOf(letter); } } } timer.cancel(); if (timeout) { System.out.println("Time's up! You took too long to guess."); } else { if (word.equals(chf)) { System.out.print("Congratulations! You've guessed the word: " + chl + "!"); } } }
额外修正点
原代码中分类选择的随机索引存在错误(如动物分类误用countries.length),已在上述代码中修正为对应数组的length属性。
内容的提问来源于stack exchange,提问作者Zahra
相关产品推荐
相关产品推荐

