无法停止在 ScheduledExecutorService.schedule 中传递自身的 Runnable

发布于 2024-12-28 02:00:32 字数 1724 浏览 1 评论 0原文

我有一个从 Runnable 实现的轮询器。轮询器将自身传递给 ScheduledExecutorService。由于我根据任务需要不同的延迟时间,因此我使用“schedule”而不是“scheduleWithFixedDelay”,这出现了问题...

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

日志显示: 一开始,“主”线程调度一个轮询器; 之后,“poller18”(或任何线程 ID)线程调度以下轮询器。

当被摧毁时, ‘main’线程调用destroy,将flag设置为true,然后调用poller.shutdown; 但“poller18”线程永远不会看到该标志(在 SchedulePoller 中始终为 false),因此它将继续调度下一个轮询器。

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

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 配置中,我将 destroy_method 设置为 destroy()。

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

I have a poller implemented from Runnable. The poller passes itself into a ScheduledExecutorService. Since I need different delay time depending on the tasks, I use 'schedule' instead of 'scheduleWithFixedDelay', which got a problem...

Unfortunately, this poller can't shut down properly...

The log shows that:
at beginning, 'main' thread schedules a poller;
after that, 'poller18' (or whatever thread id) thread schedules the following pollers.

When destroyed,
'main' thread calls destroy, set the flag to true, and then call poller.shutdown;
but 'poller18' thread never see that flag (it is always false in schedulePoller), so it will keep scheduling next pollers.

My questions are:
1. isShuttingDown is a private field in the class. I thought it would be shared by the threads since it is not ThreadLocal. Why isn't it?
2. in this situation, is there any other way poller18 can be notified that poller is shutting down?

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.");
   }
}

And in spring config, I set destroy_method to destroy().

Many thanks! Please let me know if any confusions in my description.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

泼猴你往哪里跑 2025-01-04 02:00:32

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

When accessing the shared state (isShuttingDown), whether it is read or write access, you need to always hold the same lock in order to have consistent shared state between threads.
destroy() method is not synchronized and therefore does not hold a the same object lock(the implicit lock on the current/"this" class instance), while it changes the shared state variable.
This is most probably why isShuttingDown is not seen correctly by all threads...

挽心 2025-01-04 02:00:32

尝试

private volatile boolean isShuttingDown = false;

线程池

try

private volatile boolean isShuttingDown = false;

Thread Pooling

oО清风挽发oО 2025-01-04 02:00:32

javadoc 对于执行器关闭时新计划的行为不是很清楚。根据我的理解,它应该拒绝新的时间表。

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

The javadoc isn't very clear regarding the behavior of new schedules if the executor is shutting down. In my understanding, it should reject new schedules.

Anyway, the poller thread doesn't see the value of your flag because it's not synchronized. You need to synchronize all its accesses, or to make it volatile. Another way is to use an AtomicBoolean, which will encapsulate this for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文