Executor shutdownNow с заблокированными задачами?

Я использую Executors для пула потоков и отправляю задачи. Может ли executorService.shutdownNow отключить все задачи, даже если некоторые из них могут быть заблокированы при вызовах ввода-вывода в базу данных или сокет?


person gpa    schedule 29.04.2013    source источник


Ответы (4)


Это зависит от того, хорошо ли написаны ваши задачи!

В документации говорится: "Выключение () позволит выполнить ранее отправленные задачи перед завершением, в то время как метод shutdownNow() предотвращает запуск ожидающих задач и пытается остановить выполнение текущих задач».

Однако Java не убивает потоки «из воздуха». Он пытается их прервать. Хорошая задача выдаст что-то вроде InterruptException, когда shtudownNow попытается их прервать, и завершится корректно. Вы упоминаете связь через сокеты - большинство методов блокировки приличных клиентов будут генерировать прерванное исключение, если они будут прерваны.

Примером плохой задачи может быть (довольно очевидно) запуск потока с while(true) { readChunk(); if(endOfChunks) { break;} }. Это не предлагает изящной проверки прерывания! Это старое правило: не использовать циклы while для ожидания, а wait() использовать syncronized на объекте-блокировщике, который можно прервать.

person Tom    schedule 29.04.2013
comment
Единственный способ завершить - запустить дочерний процесс вместо дочернего потока. Процесс может быть остановлен. - person gpa; 29.04.2013

Нет, гарантии нет. Если вы видите документ API для ExecutorService#shutdownNow. Он говорит,

Нет никаких гарантий, кроме как сделать все возможное, чтобы остановить обработку активно выполняющихся задач.

Если вы хотите заблокировать выполнение всех задач после запроса на завершение работы, используйте ExecutorService#awaitTermination.

person AllTooSir    schedule 29.04.2013
comment
Да, awaitTermination — идеальный вариант. - person Tom; 29.04.2013

Когда невозможно обрабатывать прерывания (java.io), требуется нестандартная логика завершения работы.

Мое решение для инкапсуляции этой проблемы сочетает в себе примеры «TrackingExecutorService» и «SocketUsingTask» из «Java Concurrency In Practice».

  • Определите интерфейс с возможностью отключения
  • Расширьте ThreadPoolExecutor для отслеживания запущенных отправленных задач, которые реализуют интерфейс «Shutdownable».
  • переопределить останов ThreadPoolExecutor для вызова нестандартной логики завершения работы через интерфейс «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
                }
            }
        }
    }

person Chomeh    schedule 02.02.2014