无法停止在 ScheduledExecutorService.schedule 中传递自身的 Runnable
我有一个从 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在访问共享状态(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...
尝试
线程池
try
Thread Pooling
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.