【问题标题】:java.lang.IllegalStateException: Task already scheduled or cancelledjava.lang.IllegalStateException:任务已安排或取消
【发布时间】:2018-04-18 19:42:25
【问题描述】:

当我启动 TimerTask 然后我完成,然后重新启动它显示此错误,为什么? 这个错误:

[16:30:02] [Client thread/INFO] [MacroSK]: KEY_L
[16:30:06] [Client thread/INFO] [MacroSK]: KEY_O
[16:30:08] [Client thread/INFO] [MacroSK]: KEY_L
[16:30:08] [Client thread/ERROR] [FML]: Exception caught during firing event net.minecraftforge.fml.common.gameevent.TickEvent$ClientTickEvent@1bc14017:
java.lang.IllegalStateException: Task already scheduled or cancelled
    at java.util.Timer.sched(Unknown Source) ~[?:1.8.0_161]
    at java.util.Timer.scheduleAtFixedRate(Unknown Source) ~[?:1.8.0_161]
    at com.skelletonx.MacroSK.handler.KeybindHandler.Shopmsg(KeybindHandler.java:53) ~[KeybindHandler.class:?]
    at com.skelletonx.MacroSK.handler.KeybindHandler.onTickEvent(KeybindHandler.java:63) ~[KeybindHandler.class:?]
    at net.minecraftforge.fml.common.eventhandler.ASMEventHandler_6_KeybindHandler_onTickEvent_ClientTickEvent.invoke(.dynamic) ~[?:?]
    at net.minecraftforge.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:55) ~[ASMEventHandler.class:?]
    at net.minecraftforge.fml.common.eventhandler.EventBus.post(EventBus.java:140) [EventBus.class:?]
    at net.minecraftforge.fml.common.FMLCommonHandler.onPostClientTick(FMLCommonHandler.java:371) [FMLCommonHandler.class:?]
    at net.minecraft.client.Minecraft.func_71407_l(Minecraft.java:2152) [bsu.class:?]
    at net.minecraft.client.Minecraft.func_71411_J(Minecraft.java:1028) [bsu.class:?]
    at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:345) [bsu.class:?]
    at net.minecraft.client.main.Main.main(SourceFile:120) [Main.class:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_161]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_161]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_161]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_161]
    at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) [launchwrapper-1.12.jar:?]
    at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.12.jar:?]

我的代码:

Timer timer = new Timer();
final TimerTask ts = new TimerTask(){
      @Override
      public void run() {
          Minecraft.getMinecraft().thePlayer.sendChatMessage(Ini.getIni("Loja"));
      }
    };
int delaymsg = Integer.parseInt(Ini.getIni("DelayL"));
public void Shopmsg() {
    timer.scheduleAtFixedRate(ts,1000*delaymsg,1000*delaymsg);
}

@SideOnly(Side.CLIENT)
@SubscribeEvent(priority=EventPriority.NORMAL, receiveCanceled=true)
public void onTickEvent(TickEvent.ClientTickEvent event) {
    if(event.phase == TickEvent.Phase.END) {
        if (mc.inGameHasFocus) {
            if (keyBindings[0].isPressed()) {
                LogHelper.info("KEY_L");
                Shopmsg();
            }
            if(keyBindings[1].isPressed()) {
                LogHelper.info("KEY_O");
                 ts.cancel();

            }
        }
    }
} 

当我完成 TaskTime 后,我该怎么做才能重新开始? 如果不停止,停止并重新启动任务时间是否可以暂停和恢复?

【问题讨论】:

    标签: java


    【解决方案1】:

    TimerTask 只能由Timer 安排一次。

    继续使用Timer,您需要每次在ShopMsg() 中重新创建一个新的TimerTask ts

    值得一提的是,Timer 现在已被ScheduledExecutorService 取代。这通常更灵活...

    例如创建执行器(代替Timer):

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
    

    然后安排循环:

        ScheduledFuture<?> future = scheduledExecutorService.scheduleAtFixedRate(
                () -> Minecraft.getMinecraft().thePlayer.sendChatMessage(Ini.getIni("Loja")),
                delaymsg, 
                delaymsg, 
                TimeUnit.SECONDS);
    

    并停止该计划:

        future.cancel(false);
    

    【讨论】:

    • scheduledExecutorService.scheduleAtFixedRate() 将立即开始循环 - 即调用您传递给它的 Runnable(在上面的示例中作为 lambda)。您只需要抓住它返回的future 即可稍后停止计划。
    • 你能举个例子(ScheduledFuture > future)我怎样才能启动ScheduledFuture。
    • 嗨,scheduledExecutorService.scheduleAtFixedRate() 已启动任务循环。一旦你准备好停止任务,你只需要future。我猜你正在寻找一种方法来暂停和恢复它作为一项任务?不幸的是,TimerTaskfuture 都没有重新启动或恢复选项 - 一旦计划被取消,它就消失了。您需要再次致电scheduleAtFixedRate() 重新开始任务。
    • 我可以在取消任务的 Future 对象后重新运行任何 TimerTask 而不重新创建任务吗?
    • 在另一种情况下也可能发生此异常! stackoverflow.com/a/69382351/7767664
    【解决方案2】:

    这种类似闭包的方法怎么样: (高级代码但仍然可爱且可行)`

    ...
    <inside method>
    ...
    class NewTimerTask extends TimerTask {
                @Override
                public void run() {
                    actionToBePerformed.run();
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            NewTimerTask.this.run();
                        }
                    }, countOffset(morningHour, eveningHour));
                }
            }
    
            timer.schedule(new NewTimerTask(), countOffset(morningHour, eveningHour));
    

    【讨论】:

      【解决方案3】:

      我总是创建一个新的TimerTask 实例,然后使用Timer 的同一实例之一来安排它。没有问题,但我仍然收到 Firebase Crashlytics 的一份报告,我认为这与线程终止计时器有关:

      所以它与重复使用 TimerTask 的同一实例无关,因为在我的情况下这是不可能的!

      所以我们需要在try...catch 中重新创建Timer 实例

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-05
        • 1970-01-01
        • 2016-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多