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.
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…