Java中Timer与TimerTask配合循环实现限时输入功能报错排查
问题:Timer已取消导致的IllegalStateException异常
需求逻辑:循环中给用户5秒输入时间,输入"atk"则从HP中减去随机数,输入其他内容则HP增加随机数,直到HP为0时终止程序。但运行代码时抛出java.lang.IllegalStateException: Timer already cancelled异常。
原代码
import java.util.Scanner; import java.util.Timer; import java.util.TimerTask; import java.util.Random; public class Main { public static void main(String[] args) { int hp = 60; Scanner sc = new Scanner(System.in); Random los = new Random(); int pc = 1 + los.nextInt(4); Timer czas = new Timer(); do{ TimerTask zd = new TimerTask(){ public void run(){ System.out.println("Czas off"); System.exit(0); } }; czas.schedule(zd, 5 * 1000); System.out.println("5 sek na odp"); String odp = sc.nextLine(); switch(odp){ case "atk": System.out.println("oo tak"); hp = hp - pc; System.out.println("hp spadlo o " + pc + " " + " wynosi " + hp); czas.cancel(); break; default: System.out.println("zle"); czas.cancel(); hp = hp + pc; System.out.println("hp wzroslo o " + pc); } } while (hp > 0); System.out.println("pokonany"); } }
控制台报错日志
5 sek na odp atk oo tak hp spadlo o 1 wynosi 59 Exception in thread "main" java.lang.IllegalStateException: Timer already cancelled. at java.base/java.util.Timer.sched(Unknown Source) at java.base/java.util.Timer.schedule(Unknown Source) at Main.main(Main.java:26) [Program finished]
错误原因
Timer对象一旦调用cancel()方法就会被永久终止,无法再复用做新的任务调度。原代码中Timer czas是在循环外初始化的,第一次循环执行czas.cancel()后,这个Timer就失效了,第二次循环再调用czas.schedule()时就会抛出异常。
另外原代码中pc随机数只生成一次,每次加减的数值都一样,不符合“随机数”的需求,也需要修正。
修复后的代码
import java.util.Scanner; import java.util.Timer; import java.util.TimerTask; import java.util.Random; public class Main { public static void main(String[] args) { int hp = 60; Scanner sc = new Scanner(System.in); Random los = new Random(); do{ // 每次循环新建Timer,避免复用已取消的Timer Timer czas = new Timer(); // 每次循环重新生成随机数,确保每次加减的数值随机 int pc = 1 + los.nextInt(4); TimerTask zd = new TimerTask(){ public void run(){ System.out.println("Czas off"); System.exit(0); } }; czas.schedule(zd, 5 * 1000); System.out.println("5 sek na odp"); String odp = sc.nextLine(); // 先取消当前Timer任务,避免超时触发退出 czas.cancel(); switch(odp){ case "atk": System.out.println("oo tak"); hp = hp - pc; System.out.println("hp spadlo o " + pc + " wynosi " + hp); break; default: System.out.println("zle"); hp = hp + pc; System.out.println("hp wzroslo o " + pc); } } while (hp > 0); System.out.println("pokonany"); } }
修复说明
- 将
Timer czas的创建移到do-while循环内部,每次循环都生成新的Timer实例,避免复用已被取消的Timer。 - 将随机数
pc的生成移到循环内部,确保每次循环的加减数值都是随机的。 - 在处理用户输入后先调用
czas.cancel(),统一取消当前Timer任务,避免代码重复。
内容的提问来源于stack exchange,提问作者DraggyCords cords
相关产品推荐
相关产品推荐

