Некоторое время я был разочарован поведением по умолчанию ThreadPoolExecutor
, которое поддерживает пулы потоков ExecutorService
, которые используют многие из нас. Цитировать из Javadocs:
Если запущено больше потоков corePoolSize, но меньше MaximumPoolSize, новый поток будет создан , только если очередь заполнена.
Это означает, что если вы определите пул потоков с помощью следующего кода, он никогда не запустит 2-й поток, поскольку LinkedBlockingQueue
не ограничен.
ExecutorService threadPool =
new ThreadPoolExecutor(1 /*core*/, 50 /*max*/, 60 /*timeout*/,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(/* unlimited queue */));
Только если у вас ограниченная очередь и очередь заполнена, запускаются все потоки выше номера ядра. Я подозреваю, что многим многопоточным программистам младшего возраста Java не известно о таком поведении ThreadPoolExecutor
.
Теперь у меня есть конкретный случай использования, где это неоптимально. Я ищу способы, без написания своего собственного класса TPE, чтобы обойти это.
Мои требования касаются веб-службы, которая выполняет обратные вызовы, возможно, ненадежной третьей стороне.
- Я не хочу выполнять обратный вызов синхронно с веб-запросом, поэтому я хочу использовать пул потоков.
- Обычно я получаю пару таких минут, поэтому я не хочу иметь
newFixedThreadPool(...)
с большим количеством потоков, которые в основном неактивны. - Время от времени я получаю всплеск этого трафика и хочу увеличить количество потоков до максимального значения (скажем, 50).
- Мне нужно сделать лучшую попытку выполнить все обратные вызовы, поэтому я хочу поставить в очередь любые дополнительные вызовы выше 50. Я не хочу перегружать остальную часть моего веб-сервера с помощью
newCachedThreadPool()
.
Как можно обойти это ограничение в ThreadPoolExecutor
, где очередь должна быть ограничена и заполнена, прежде чем будет запущено больше потоков? Как я могу заставить его запускать больше потоков перед очередью задач?
Изменить:
@Flavio хорошо описывает использование ThreadPoolExecutor.allowCoreThreadTimeOut(true)
для тайм-аута основных потоков и выхода из него. Я считал это, но я все еще хотел функцию основных потоков. Я не хотел, чтобы количество потоков в пуле упало ниже размера ядра, если это возможно.