Потоки демона, запланированные на ExecutorService;объяснить, почему это плохо - PullRequest
20 голосов
/ 23 августа 2011

Я доволен идеей упорядоченного отключения потоков, запланированных с ExectuorService; то есть, вызов shutdown или shutdownNow приведет к корректному завершению потоков, созданных в пуле. Если они ответят на interrupt, вы можете быть уверены, что, наконец, и т. Д. Будет вызван, и вы получите чистый, предсказуемый выход (где вы можете очистить любые ресурсы и т.д.).

Однако, если вы указали в своей нити демон (через ThreadFactory исполнителя), как показано ниже.

ExecutorService pool = Executors.newSingleThreadExecutor(new ThreadFactory() {
   @Override
   public Thread newThread(Runnable runnable) {
      Thread thread = Executors.defaultThreadFactory().newThread(runnable);
      thread.setDaemon(true);
      return thread;
   }
});

после того, как основной поток завершает работу, виртуальная машина прерывает любые потоки демона. В приведенном выше примере запланированный, а затем внезапно завершенный поток (daemon) будет обходить любые блоки finally, а любые прерываемые методы не будут выбрасывать InterruptedException.

Итак, я склонен считать, что маркировка потоков, используемых в пуле ThreadPoolExecutor, как дьявола - плохая практика ... мой вопрос на самом деле о том, чтобы помочь мне вокализировать почему .

Почему плохая практика (или нет, если вы не согласны) использовать потоки демона в пуле потоков ExecutorService? В частности, меня интересует описание жизненного цикла завершения работы виртуальной машины с постепенным завершением работы (потоки, которые имеют политику прерывания и работают хорошо) против потоков демона.

Расширяя эту последнюю точку, finalize на ThreadPoolExecutor вызовет shutdown для себя, но когда он использует потоки демона, они могли бы завершиться уже, если бы виртуальная машина вызвала finalize. Каково поведение пула потоков тогда? Можно ли обмануть его, чтобы он оставался живым (и, следовательно, не выходил из ВМ), если базовые потоки внезапно завершались?

Частично причина, по которой я спрашиваю, состоит в том, что я видел, как раньше она обходила необходимость выключать фактическую службу ExectorService. Можете ли вы вспомнить сценарии, в которых обход его жизненного цикла выключения может оказать плохое влияние? Пока что единственная причина, по которой я могу придумать использование демонов, - это сократить путь, и я хочу оценить любые неожиданные побочные эффекты, которые это может вызвать.

Ответы [ 3 ]

14 голосов
/ 23 августа 2011

является ли плохой практикой использование потоков демонов в пуле потоков ExecutorService?

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

finalize() вызывается, когдаобъект собирается быть мусором .Нет никаких гарантий, когда, если вообще когда-либо, какой-либо конкретный объект будет GCd, и ThreadPoolExecutor не является исключением, поэтому его finalize() может вызываться или не вызываться.Поведение зависит от конкретной реализации JRE и даже с одной и той же реализацией может время от времени меняться.

5 голосов
/ 06 января 2012

Потоки демона могут быть полезны, и если бы они не были прерваны внезапно, они не были бы такими полезными для IMO.

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

С другой стороны, если у вас есть задачи, которые не требуют очистки при завершении работы, потоки deamon весьма удобны. И вы не хотели бы тратить время на ожидание их прихода в какое-то конкретное состояние или риска зависания при завершении работы и т. Д., Потому что причина, по которой вы используете поток демона, заключается в том, что вам не нужна какая-либо очистка. Это было бы пустой тратой времени, чтобы выполнить что-либо, если приложение. закрывается Если вам не безразлично, то вам не следовало использовать нити демона.

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

Из книги JCiP :

Потоки демонов следует использовать редко, но некоторые операции обработки могут быть безопасно прекращены в любое время без очистки. В частности, опасно использовать потоки демона для задач, которые могут выполнять любые операции ввода-вывода. Потоки демона лучше всего сохранять для выполнения «служебных» задач, таких как фоновый поток, который периодически удаляет просроченные записи из кэша в памяти

5 голосов
/ 23 августа 2011

Я склонен иметь разные пулы для потоков демона и не демона.Пулы демонов, как правило, выполняют повторяющиеся задания по очистке, мониторингу и фоновым задачам, которые не имеют значения, если один или два не выполняются.Любая задача, которая имеет смысл только во время работы приложения, хороша для создания задачи потока демона.например, потоки GC являются потоками демона.

...