如何取消已调度的Java Timer定时任务并重新运行?Minecraft Forge开发问题
问题根源
修改后取消逻辑不生效的核心原因是变量作用域错误:
你在K键触发的启动逻辑中,新创建的Timer是局部变量,仅在当前if代码块内生效,KeyBind类的成员变量timer仍指向最初创建、已经被取消的旧实例。按下L键执行取消时,调用的是旧实例的cancel()方法,自然无法终止新启动的定时任务。
修复方案
核心修改点
- 启动任务时直接给成员变量
timer赋值,不要声明局部变量 - 新增非空判断避免空指针异常
- 可选优化:给状态变量和Timer变量加
volatile修饰,保证多线程场景下的变量可见性 - 可选优化:TimerTask的死循环中加入小段休眠,降低CPU占用
修复后代码
KeyBind类代码
public class KeyBind { // 加volatile保证多线程可见性 public static volatile Boolean Status = false; volatile Timer timer = new Timer(); @SubscribeEvent public void onKeyPressed(InputEvent.KeyInputEvent event) throws InterruptedException { // K键启动逻辑 if (ForgeMain.keybinding.isKeyDown()) { if(Status == false) { EntityPlayerSP entityPlayerSP = (Minecraft.getMinecraft()).thePlayer; entityPlayerSP.addChatComponentMessage((IChatComponent) new ChatComponentText(EnumChatFormatting.YELLOW + "You have successfully ran the NetherWart Macro!")); Status = true; // 直接给成员变量赋值,不要声明局部Timer timer = new Timer(); timer.schedule(new Left(), 100, 38000); timer.schedule(new Forward(), 33100, 38000); timer.schedule(new Right(), 35100, 38000); } } // L键取消逻辑 if(ForgeMain.keybinding1.isKeyDown()){ if(Status == true) { Status = false; System.out.println(Status.booleanValue()); // 加非空判断避免空指针 if (timer != null) { timer.cancel(); timer.purge(); } } } } }
TimerTask优化(可选,降低CPU占用)
public class Right extends TimerTask { @Override public void run() { int keyCode = Minecraft.getMinecraft().gameSettings.keyBindRight.getKeyCode(); long oldTime = System.currentTimeMillis(); KeyBinding.setKeyBindState(keyCode, true); while (System.currentTimeMillis() - oldTime < 33000) { // 加10ms休眠,几乎不影响操作手感,大幅降低CPU占用 try { Thread.sleep(10); } catch (InterruptedException e) { // 任务被中断时直接释放按键,退出循环 break; } } KeyBinding.setKeyBindState(keyCode, false); } }
内容的提问来源于stack exchange,提问作者Can Tam
相关产品推荐
相关产品推荐

