You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java控制台版Hangman游戏超时功能异常问题求助

解决Hangman游戏超时后循环不终止的问题

问题根源

  1. Scanner阻塞:scanner.nextLine()是阻塞方法,主线程会一直停在这里等待用户输入,即使20秒超时后timeout变为true,也无法进入循环条件判断或执行break语句。
  2. 内存可见性: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:32:09