我有一个从Runnable实现的轮询器。轮询器将自己传递到ScheduledExecutiorService中。由于根据任务的不同,我需要不同的延迟时间,所以我使用了"schedule"而不是"scheduleWithFixedDelay",这遇到了问题。。。
不幸的是,这个轮询器无法正常关闭。。。
日志显示:一开始,"main"线程调度一个轮询器;之后,"poller18"(或任何线程id)线程调度以下轮询器。
当被破坏时,"main"线程调用destroy,将标志设置为true,然后调用poller.shutdown;但"poller18"线程从未看到该标志(在schedulePoller中它总是false),因此它将继续调度下一个轮询器。
我的问题是:1.isShuttingDown是该类中的一个私有字段。我以为它会被线程共享,因为它不是ThreadLocal。为什么不是?2.在这种情况下,是否有其他方式可以通知poller 18 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-config中,我将destroy_method设置为destroy()。
非常感谢!如果我的描述有任何混淆,请告诉我。
访问共享状态(isShuttingDown)时,无论是读访问还是写访问,都需要始终持有相同的锁,以便在线程之间保持一致的共享状态。destroy()方法不同步,因此在更改共享状态变量时,它不持有相同的对象锁(当前/"this"类实例上的隐式锁)。这很可能是所有线程都不能正确看到isShuttingDown的原因。。。
尝试
private volatile boolean isShuttingDown = false;
线程池
如果执行器关闭,javadoc对新调度的行为不是很清楚。根据我的理解,它应该拒绝新的时间表。
无论如何,轮询线程看不到您的标志的值,因为它没有同步。您需要同步它的所有访问,或者使其不稳定。另一种方法是使用AtomicBoolean,它将为您封装它。