问题
I have a scheduled Executor service setup like
class Test {
private final ScheduledExecutorService executor;
public Test() {
executor = Executors.newSingleThreadScheduledExecutor((runnable) -> {
Thread thread = new Thread(runnable, this.getClass().getName());
thread.setDaemon(true);
return thread;
});
executor.scheduleWithFixedDelay(
new TestRefreshTask(), 0, 50000, TimeUnit.MILLISECONDS
);
}
private class TestRefreshTask implements Runnable {
@Override
public void run() {
//refresh some data
refreshdata();
}
}
public void close() {
executor.shutdown();
try {
if(!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
executor.awaitTermination(60, TimeUnit.SECONDS));
}
} catch (InterruptedException e) {
//Retry to dispose task
executor.shutdownNow();
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
}
To stop this thread I call the close method but often the thread doesn't stop. I am not sure what's wrong and if somehow I am supposed to handle the InterruptedException
in my run() code.
回答1:
- Real solution below the line. This part only describes the pitfalls.
From the javadoc of shutdownNow()
:
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt, so any task that fails to respond to interrupts may never terminate.
From experience, threads do indeed get interrupted, but according to this documentation even that is not guaranteed.
However, your task is not something you control yourself, it's private task created within scheduleWithFixedDelay()
.
From the javadoc of scheduleWithFixedDelay()
:
If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor.
This means that shutdownNow()
will not stop the thread. The cancellation part is a bit unclear to me since a Runnable
, as opposed to a Future
, does not have a cancel()
method. The other reason a task will stop is termination of the executor, however the pool only terminates when the tasks stop.
The real solution lurks in this part from the javadoc of ScheduledThreadPoolExecutor
:
By default, such a cancelled task is not automatically removed from the work queue until its delay elapses. While this enables further inspection and monitoring, it may also cause unbounded retention of cancelled tasks. To avoid this, set setRemoveOnCancelPolicy to true, which causes tasks to be immediately removed from the work queue at time of cancellation.
When you order the executor to stop, it sets the interrupted flag, and if it's a ScheduledThreadPoolExecutor
, removes the task if the removeOnCancelPolicy
is true.
Solution:
- Execute
executor.setRemoveOnCancelPolicy(true)
before submitting the schedule.
[edit]: Since you use the factory method, this is not possible to implement directly.
Make these changes:
private final ScheduledThreadPoolExecutor executor;
executor = new ScheduledThreadPoolExecutor(1, (runnable) -> {
来源:https://stackoverflow.com/questions/38826985/executorservice-shutdownnow-doesnt-stop-the-thread