【问题标题】:Java ScheduledExecutorService cancel doesn't workJava ScheduledExecutorService 取消不起作用
【发布时间】:2017-03-02 05:56:25
【问题描述】:

我使用ScheduledExecutorService 启动了一个定期运行的计时器,但是在我调用cancel() 后,这个计时器无法取消:

import java.util.concurrent.*;

public class Monitor {
    private static ScheduledFuture<?> timerCtrl;
    private final ScheduledExecutorService scheduExec = Executors.newScheduledThreadPool(1, StatmonitorThreadFactory.getInstance());

    private void startTimer() {
        timerCtrl = scheduExec.scheduleAtFixedRate(new MonitorTimer(), 5, 5, TimeUnit.SECONDS);
    }

    public boolean cancelMonitorTimer() {
        if (timerCtrl != null) {
            timerCtrl.cancel(false); //both timerCtrl.isDone() and timerCtrl.isCancelled() return true
            LOG.error("{} {}", timerCtrl.isDone(), timerCtrl.isCancelled());
            if (!timerCtrl.isCancelled()) {
                LOG.error("timerCtrl cancel failed!");
                return false;
            }
        }
        return true;
    }

    private class MonitorTimer implements Runnable {
        @Override
        public void run() {
            doPeriodicMonitor(); //call another function
        }
    }
}

首先,我打电话给startTimer() 来启动我的计时器。过了一会儿,我调用cancelMonitorTimer取消并停止这个定时器,函数返回true,但定时器仍然运行,doPeriodicMonitor每5秒调用一次,这是我在startTimer中设置的一个周期。

【问题讨论】:

  • 如果监视任务花费的时间超过 5 秒并且线程池已耗尽,这将是预期的行为。您应该添加日志记录以记录 doPeriodicMonitor 的延迟,然后确保计划的速率较慢。您还应该在没有线程池的情况下尝试它以排除那里的错误。
  • @Gene 在doPeriodicMonitor(),我启动另外两个线程来做一些工作,是非法的吗?

标签: java timer


【解决方案1】:

您需要在 cancelMonitorTimer() 方法中将 true 设置为 timeCrtl.cancel(true) 而不是 timerCtrl.cancel(false)。如果任务取消成功,该函数进一步返回布尔值true,如果返回false,则表示已经完成。

【讨论】:

  • 不行,mayInterruptIfRunning - true if the thread executing this task should be interrupted; otherwise, in-progress tasks are allowed to complete,参数意思是中断正在运行的线程。在这种情况下,我的函数 doPeriodicMonitor 每 5 秒调用一次
【解决方案2】:

我找到了在定义timerCtrl 时不应该使用限定符static 的原因。但我仍然不知道为什么不能。在我的理解中,静态值是 per-class-loader 而不是per-thread,所以这个变量将在不同的线程之间共享。
另外,Monitor类是一个基类,被另一个类MonitorSon继承,操作在子类中调用。

【讨论】:

  • static 字段是每个类加载器。根据您引用的答案,当多个线程在竞争条件和内存共享方面更新相同的static 字段时存在同步问题,但它们仍然是相同的字段。如果thread1分配timeCtrl,那么如果它是静态thread2将覆盖thread1的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-12
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-18
  • 1970-01-01
相关资源
最近更新 更多