2

我正在使用 Executors 进行线程池,并提交任务。executorService.shutdownNow 是否可以关闭所有任务,即使其中一些任务可能在对数据库或套接字的 I/O 调用中被阻塞?

4

4 回答 4

4

这取决于你的任务写得好不好!

文档说: “ shutdown() 方法将允许先前提交的任务在终止之前执行,而 shutdownNow() 方法阻止等待任务启动并尝试停止当前正在执行的任务。”

但是,Java 不会“凭空”杀死线程。它试图打断他们。InterruptException当 shtudownNow 试图打断它们并优雅地结束时,一个好的任务会抛出某种类型的。你提到了套接字通信——如果它们被中断,大多数体面的客户端的阻塞方法都会抛出一个中断的异常。

一个坏任务的例子可能是(很明显)用while(true) { readChunk(); if(endOfChunks) { break;} }. 这不提供优雅的中断检查!旧规则不使用 while 循环等待,而是wait()使用syncronized可以被中断的“阻塞”对象。

于 2013-04-29T16:36:11.083 回答
1

不,没有保证。如果您看到ExecutorService#shutdownNow的 API 文档。它说,

除了尽最大努力停止处理正在执行的任务之外,没有任何保证。

如果您想在关闭请求后阻塞直到所有任务都完成执行,请使用ExecutorService#awaitTermination

于 2013-04-29T16:32:22.563 回答
1

当无法处理中断(java.io)时,需要非标准的关闭逻辑。

我封装这个问题的解决方案结合了来自“Java Concurrency In Practice”的示例“TrackingExecutorService”和“SocketUsingTask”。

  • 定义一个“可关闭”接口
  • 扩展 ThreadPoolExecutor 以跟踪实现“可关闭”接口的正在运行的提交任务
  • 覆盖 ThreadPoolExecutor 的 shutdownNow 以通过 'Shutdownable' 接口调用非标准关闭逻辑


    public interface Shutdownable {
        public void shutdown();
    }

    public class ShutdowningExecutor extends ThreadPoolExecutor{
        private final Set runningShutdownables 
            = Collections.synchronizedSet(new HashSet());

        @Override
        protected RunnableFuture newTaskFor(final Callable callable){
            if (callable instanceof Shutdownable) {
            runningShutdownables.add((Shutdownable) callable);          
            return super.newTaskFor(new Callable(){
                    @Override
                    public T call() throws Exception {
                T t = callable.call();
                runningShutdownables.remove((Shutdownable) callable);
                        return t;
                    }
                 });
            } else
                return super.newTaskFor(callable);
        }

        public void shutdownAll() {
            for(Shutdownable shutdownable : runningShutdownables) {
                shutdownable.shutdown();
            }
        }

        @Override
        public List shutdownNow(){
            shutdownAll();
            return super.shutdownNow();
        }
    }

    public abstract class ShutdownableViaCloseable implements Shutdownable{
        private Closeable closeable;

        protected synchronized void setCloseable(Closeable c) { closeable = c; }

        public synchronized void shutdown() {
           try {
               if (closeable != null)
             closeable.close();
           } catch (IOException ignored) { }
       }
    }

    public class MySocketTask extends ShutdownableViaCloseable implements Callable {
        public MySocketTask(Socket s) {
            setCloseable(s);
            //constructor stuff
        } 

        public Void call() {
            try (Socket socket = this.socket) {
                while(!socket.isClosed) {
                    //do stuff
                }
            }
        }
    }

于 2014-02-02T02:32:07.550 回答
0

简单地说:你不能依赖它。ExecutorService简单地中断正在运行的任务;如果他们真的取消他们的努力,这取决于任务的执行。一些 I/O 可以(并且将会)被中断,尤其是那些java.nio东西,但java.io很可能不会被中断。请参阅java.lang.Thread.interrupt() 做什么?更多解释。

于 2013-04-29T16:39:14.780 回答