从 运行 任务关闭 ExecutorService

Shutting down an ExecutorService from running task

我正在使用单线程 ScheduledExecutorService 来处理一些 Runnable 任务。当我的 Runnable 完成工作时,它会在 ScheduledExecutorService 中以可变延迟重新安排自己。这种情况会无限期地发生,直到 Runnable 捕获到 Exception

public class Runner { 

    ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

    public void startWorking() { 
        // Single-shot start
        service.submit(new Task(service));
    }

    public void stopWorking() { 
        service.shutDown();
        // Do some other stuff
    }

    private static final class Task implements Runnable { 
        ScheduledExecutorService service;
        private Task(ScheduledExecutorService service) {
            this.service = service;
        }
        @Override 
        public void run() { 
            try { 
                // Do some work...
                service.schedule(this, variableDelay, TimeUnit.SECONDS);
            }
            catch(SomethingHappenedException e){ 
                // Shutdown service
            }
        }
    }   
}

我可以 shutdown()shutdownNow() ExecutorService 安全地离开 Task.run() 吗?如果线程将对自身产生中断,则有些事情看起来不对。

当执行 Task 时捕获到异常时,我想 shutdown service,最好调用 Runner.stopWorking()

我知道我可以改用 Callable 并让 Runner 管理重新安排,但我想保留此结构(Runner 将有更多类似的 services,所以无限循环看起来并不正确)。

我想我可以使用对 Runner.

的引用来继承 ScheduledThreadPoolExecutor 来覆盖 afterExecute 并在那里处理关闭
public class Runner { 
    ScheduledExecutorService service = new ScheduledThreadPoolExecutor(1){
      protected void afterExecute(Runnable r, Throwable t) { 
        if (t != null) { 
            Runner.this.stopWorking();
        }
    };
    // ...
}

我对这种方法的担忧是,如果 afterExecute 将由 运行 和 Task 的线程调用,这将与调用 shutDown() 产生相同的效果来自 Task.run() 本身。

还有其他替代方法吗?

Can I shutdown() or shutdownNow() the ExecutorService safely from Task.run()? Something doesn't look right if the thread will be provoking an interrupt to itself.

shutdown() 不会中断已经 运行 的任务,但会阻止提交新任务。 shutdownNow() 也不会中断 运行 任务,但是 "signals" 所有工人都应该被终止。这取决于 Thread 实现(或者更确切地说 Runnable 本身)是否会接受这样的信号(Thread.isTerminated(),我记得)。

是的,线程发出终止信号是完全没问题的。因此 shutdown() 执行者从 运行 任务是安全的。