我有一个从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()。
非常感谢!如果我的描述有任何混淆,请告诉我。
答案 0 :(得分:0)
答案 1 :(得分:0)
如果执行程序正在关闭,javadoc对新计划的行为不是很清楚。根据我的理解,它应该拒绝新的时间表。
无论如何,轮询器线程没有看到你的标志的值,因为它没有同步。您需要同步其所有访问,或使其易变。另一种方法是使用AtomicBoolean,它会为你封装它。
答案 2 :(得分:0)
当访问共享状态(isShuttingDown)时,无论是读取还是写入访问,都需要始终保持相同的锁定,以便在线程之间保持一致的共享状态。 destroy()方法不是同步的,因此它不会保持相同的对象锁定(当前/“this”类实例上的隐式锁定),同时它会更改共享状态变量。 这很可能是为什么所有线程都没有正确看到ShuutDown ...