executorService.shutdownNow() doesn't stop the thread

廉价感情. 提交于 2021-01-28 19:41:02

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!