无法阻止在ScheduledExecutorService.schedule中传递自己的Runnable

时间:2012-01-19 08:48:22

标签: java runnable executorservice

我有一个从Runnable实现的轮询器。轮询器将自身传递给ScheduledExecutorService。由于我需要不同的延迟时间取决于任务,我使用'schedule'而不是'scheduleWithFixedDelay',这有问题......

不幸的是,这个轮询器无法正常关闭......

日志显示: 在开始时,'main'线程安排一个轮询器; 之后,'poller18'(或任何线程ID)线程安排以下轮询器。

被摧毁时 'main'线程调用destroy,将标志设置为true,然后调用poller.shutdown; 但是'poller18'线程永远不会看到那个标志(它在schedulePoller中总是为false),所以它将继续调度下一个轮询器。

我的问题是: 1. isShuttingDown是该类中的私有字段。我认为它会被线程共享,因为它不是ThreadLocal。为什么不呢? 2.在这种情况下,有没有其他方法可以通知poller18轮询器正在关闭?

class Poller implements Runnable {
    private boolean isShuttingDown = false;
    private ScheduledExecutorService poller = null;

    @PostConstruct
    protected synchronized void start() {
      if (enabled && poller == null) {
          poller = Executors.newScheduledThreadPool(1);
          schedulePoller(1);
      }
   }

   protected synchronized void schedulePoller(final long period) {
      if (poller() == null || poller().isShutdown() || this.isShuttingDown) {
          return;
      }
      LOGGER.info("schedule a new poller");
      poller().schedule(this,
              period,
              TimeUnit.MILLISECONDS);
   }

   public void run() {
      ... do work ...
      if (more work)
           schedulePoller(1);
      else
           schedulePoller(10);
   }

   public void destroy() {
      this.isShuttingDown = true;
      poller.shutdown();
      while (!poller.awaitTermination(SHUTDOWN_WAIT_SECONDS, TimeUnit.SECONDS)) {
          LOGGER.info("Waiting for remaining tasks to finish.");
          poller.shutdown();
      }
      LOGGER.info("All remaining tasks have finished.");
   }
}

在spring config中,我将destroy_method设置为destroy()。

非常感谢!如果我的描述有任何混淆,请告诉我。

3 个答案:

答案 0 :(得分:0)

尝试

private volatile boolean isShuttingDown = false;

Thread Pooling

答案 1 :(得分:0)

如果执行程序正在关闭,javadoc对新计划的行为不是很清楚。根据我的理解,它应该拒绝新的时间表。

无论如何,轮询器线程没有看到你的标志的值,因为它没有同步。您需要同步其所有访问,或使其易变。另一种方法是使用AtomicBoolean,它会为你封装它。

答案 2 :(得分:0)

当访问共享状态(isShuttingDown)时,无论是读取还是写入访问,都需要始终保持相同的锁定,以便在线程之间保持一致的共享状态。 destroy()方法不是同步的,因此它不会保持相同的对象锁定(当前/“this”类实例上的隐式锁定),同时它会更改共享状态变量。 这很可能是为什么所有线程都没有正确看到ShuutDown ...