Выключить ExecutorService изящно в webapp?
В моем webapp я создал службу, которая использует ExecutorService
с фиксированным размером ThreadPool. Я использую один и тот же ExecutorService
в течение всего срока службы приложения.
private static ExecutorService pool = Executors.newFixedThreadPool(8);
Все работает в Tomcat, что дает мне следующую ошибку при отключении:
appears to have started a thread named [pool-1-thread-1] but has failed to stop it. This is very likely to create a memory leak.
Я понимаю, что мне нужно выключить ExecutorService, прежде чем отключить tomcat. Soms SO thread уже говорит об этом, но я не мог найти чистый способ справиться с этим.
Должен ли я использовать ShutdownHook
как предложено @Tim-bender в Изящное завершение потоков и исполнителей? Или я должен использовать CachedThreadPool?
Ответы
Ответ 1
Завершающий крючок не подходит для Tomcat, потому что:
-
он закроет пул слишком поздно (при выключении), Tomcat уже предупредит вас о не закрытых ресурсах
-
вы действительно хотите закрыть этот пул, когда приложение не развернуто, так что перераспределение работает (иначе каждое приложение создаст новый пул, и все они будут закрыты только при полном завершении работы)
-
Завершение пула потоков может занять некоторое время (см. ниже), крюк отключения должен быть как можно быстрее
Намного лучше - ServletContextListener.contextDestroyed()
. Помните, что у вас есть как shutdownNow()
пул (чтобы отменить запуск и отклонить новые задачи), так и awaitTermination()
, чтобы дождаться завершения уже запущенных задач и остановить все потоки.
Ответ 2
В дополнение к тому, что предложил Томаш, вы также можете использовать CachedThreadPool
Нити, которые не использовались в течение шестидесяти секунд, завершаются и удаляются из кеша. Таким образом, пул, который остается бездействующим достаточно долго, не будет потреблять какие-либо ресурсы
Таким образом, очень хорошим решением будет использование CachedThreadPool
и выключение его в ServletContextListener.contextDestroyed()
.