2013-11-18 1 views
19

Я положил кучу работоспособных объектов в ExecutorService:программа не завершается сразу, когда все задачи ExecutorService сделаны

// simplified content of main method 
ExecutorService threadPool = Executors.newCachedThreadPool(); 
for(int i = 0; i < workerCount; i++) { 
    threadPool.execute(new Worker()); 
} 

Я ожидаю, что моя программа/процесс немедленно прекратить после того, как все рабочие сделали. Но согласно моему журналу, это займет еще 20-30 секунд, пока это не произойдет. Работники не выделяют никаких ресурсов, фактически они ничего не делают на данный момент.

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

ответ

23

Executors.newCachedThreadPool() использует Executors.defaultThreadFactory() для своих ThreadFactory. defaultThreadFactory javadocs говорят, что «каждый новый поток создается как не-daemon поток» (выделено мной). Итак, потоки, созданные для newCachedThreadPool, являются не-демонами. Это означает, что они будут препятствовать естественному выходу JVM («естественно», я имею в виду, что вы все равно можете позвонить System.exit(1) или убить программу, чтобы заставить JVM остановиться).

Причина, по которой приложение заканчивается вовсе, заключается в том, что каждая нить, созданная в пределах newCachedThreadPool, разрывается и закрывается после некоторого времени бездействия. Когда последний из них закрывается, если ваше приложение не имеет ни одного не-демона, то оно прекратится.

Вы можете (и должны) закрыть ExecutorService вниз вручную через shutdown или shutdownNow.

См. Также JavaDoc для Thread, в котором говорится о демонах.

+1

Понял, спасибо за ваш подробный ответ на мой вопрос. – alapeno

+0

Хотя это будет работать, правильный ответ заключается в том, что вы _must_ завершите работу 'ExecutorService' @alapeno. – Gray

+0

@Gray: Нет, посмотрите в Javadoc, который я цитировал в своем ответе, - эти потоки автоматически выключаются, если они простаивают в течение 60 секунд. –

3

Из javadoc для Executors.newCachedThreadPool():

Нити, которые не использовались в течение шестидесяти секунд прекращается, и удаляется из кэша.

Это, как правило, хорошая идея, чтобы позвонить shutdown() на ExecutorService, если вы знаете, что никакие новые задачи не будут представлены в нем. Затем все задачи в очереди будут завершены, но служба немедленно отключится.

(Альтернативно, если вам все равно, выполняются ли все задачи, например, если они обрабатывают фоновые вычисления, которые не имеют значения после того, как ваш основной интерфейс исчезнут, - тогда вы можете создать ThreadFactory, который устанавливает все потоки в этот пул будет демоном.)

+0

Спасибо за подсказку вызывать shutdown(), imho это подходит для моего сценария – alapeno

+0

После вызова shutdown() вам также нужно вызвать waitTerminate (...). Shutdown() не ожидает завершения ранее поставленных задач. См. Также http://stackoverflow.com/questions/1250643/how-to-wait-for-all-threads-to-finish-using-executorservice –

4

Я ожидаю, что моя программа/процесс остановится сразу после того, как все работники будут сделаны. Но согласно моему журналу, это займет еще 20-30 секунд, пока это не произойдет. Работники не выделяют никаких ресурсов, фактически они ничего не делают на данный момент.

Проблема в том, что вы не закрываете свой ExecutorService. После того, как вы отправите все задания в службу, вы должны завершить работу службы, или JVM не будет завершаться, если все потоки в нем не являются потоками демона. Если вы не отключите пул потоков, то любые потоки, связанные с ExecutorService, опять же, если не демон, остановят JVM от завершения. Если вы отправили какие-либо задачи в кешированный пул потоков, вам придется подождать, пока потоки перейдут на тайм-аут и получат прибыль до завершения JVM.

ExecutorService threadPool = Executors.newCachedThreadPool(); 
for(int i = 0; i < workerCount; i++) { 
    threadPool.execute(new Worker()); 
} 
// you _must_ do this 
threadPool.shutdown(); 

Запуск темы, как демон, скорее всего, не то, что вы хотите сделать, потому что ваше приложение может перестать до того задача была завершена, и все задачи, будет немедленно прекращена в то время. Из 178 раз мы используем классы ExecutorService в нашем производственном коде, только 2 из них были запущены как потоки демонов. Остальные нормально завершают работу.

Если вам необходимо принудительно отключить ExecutorService, когда приложение выходит, то с помощью shutdownNow() с правильной обработкой флагов прерывания потока в порядке.

+2

Каково ваше определение «must»? Javadocs для ExecutorService не говорят, что это «должно» быть закрыто (просто это «может быть»), и ваше утверждение о том, что он будет висеть (а не «может» зависать), является либо повторением вопроса OP, либо просто неверно, в зависимости от того, как вы определяете «зависание». Я согласен с тем, что это хорошая практика, чтобы закрыть «ExecutorService», но если вы собираетесь спускать вниз и пытаетесь сделать это утверждение три раза по этому вопросу, честно говоря, я думаю, что вам нужно его поддержать. – yshavit

+0

Я изменил свой ответ @yshavit, чтобы добавить более подробную информацию. Хотя javadocs действительно говорят, что он «может», если вы не отключите его, JVM не завершится. Я пишу 100 из реализаций «ExecutorService», и я редко настраивал их как не-демона. Выключение их в конце - правильный шаблон. – Gray

+0

Достаточно честный, и в любом случае достаточно хорошей практики, чтобы быть почти обязательным. – yshavit

0

Для многопоточной обработки ExecutorService Решение threadPool.shutdown();

3

В основном на ExecutorService вызове Shutdown(), а затем awaitTermination():

ExecutorService taskExecutor = Executors.newFixedThreadPool(4); 
while(...) { 
    taskExecutor.execute(new MyTask()); 
} 
taskExecutor.shutdown(); 
try { 
    taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 
} catch (InterruptedException e) { 
    ... 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^