Кажется, невозможно создать пул кэшированных потоков с ограничением количества потоков, которые он может создать.
Вот как статический Executors.newCachedThreadPool реализован в стандартной библиотеке Java:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
Итак, используя этот шаблон для создания пула кэшированных потоков фиксированного размера:
new ThreadPoolExecutor(0, 3, 60L, TimeUnit.SECONDS, new SynchronusQueue<Runable>());
Теперь, если вы воспользуетесь этим и отправите 3 задачи, все будет хорошо. Отправка любых дальнейших задач приведет к отклонению исключений выполнения.
Пробуем это:
new ThreadPoolExecutor(0, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runable>());
В результате все потоки будут выполняться последовательно. То есть пул потоков никогда не будет создавать более одного потока для обработки ваших задач.
Это ошибка в методе выполнения ThreadPoolExecutor? А может это намеренно? Или есть другой способ?
Изменить: мне нужно что-то точно такое же, как пул кэшированных потоков (он создает потоки по запросу, а затем убивает их после некоторого тайм-аута), но с ограничением количества потоков, которые он может создать, и возможностью продолжать ставить в очередь дополнительные задачи после того, как он достигнет своего предела потока. Согласно ответу Sjlee, это невозможно. Глядя на метод execute () ThreadPoolExecutor, это действительно невозможно. Мне нужно было бы создать подкласс ThreadPoolExecutor и переопределить execute () примерно так, как это делает SwingWorker, но то, что SwingWorker делает в своем execute (), - это полный взлом.
источник
Ответы:
ThreadPoolExecutor имеет следующие несколько основных поведений, и ваши проблемы можно объяснить этим поведением.
Когда задачи отправлены,
В первом примере обратите внимание, что размер SynchronousQueue по существу равен 0. Поэтому, как только вы достигнете максимального размера (3), сработает политика отклонения (# 4).
Во втором примере предпочтительной очередью является LinkedBlockingQueue неограниченного размера. Следовательно, вы застреваете в поведении №2.
Вы не можете сильно повозиться с кешированным или фиксированным типом, поскольку их поведение почти полностью определено.
Если вы хотите иметь ограниченный и динамический пул потоков, вам необходимо использовать положительный размер ядра и максимальный размер в сочетании с очередью конечного размера. Например,
Приложение : это довольно старый ответ, и похоже, что JDK изменил свое поведение, когда дело доходит до размера ядра 0. Начиная с JDK 1.6, если размер ядра равен 0 и в пуле нет потоков, ThreadPoolExecutor добавит поток для выполнения этой задачи. Следовательно, размер ядра 0 является исключением из приведенного выше правила. Благодаря Steve для чего , что мое внимание.
источник
allowCoreThreadTimeOut
чтобы этот ответ был идеальным. См. Ответ @ user1046052Если я что-то не упустил, ответ на исходный вопрос прост. Следующий код реализует желаемое поведение, как описано на исходном плакате. Он создаст до 5 потоков для работы с неограниченной очередью, а незанятые потоки завершатся через 60 секунд.
источник
Была такая же проблема. Поскольку никакой другой ответ не объединяет все проблемы, я добавляю свой:
Теперь это четко написано в документации : если вы используете очередь, которая не блокирует (
LinkedBlockingQueue
), настройка максимального количества потоков не имеет никакого эффекта, используются только основные потоки.так:
У этого исполнителя есть:
Нет концепции максимальных потоков, поскольку мы используем неограниченную очередь. Это хорошо, потому что такая очередь может привести к тому, что исполнитель создаст огромное количество неосновных, дополнительных потоков, если он будет следовать своей обычной политике.
Очередь максимального размера
Integer.MAX_VALUE
.Submit()
будет выбрасывать,RejectedExecutionException
если количество ожидающих задач превышаетInteger.MAX_VALUE
. Не уверен, что сначала у нас закончится память, или это произойдет.Имеет 4 возможных основных потока. Неактивные основные потоки автоматически завершаются, если они простаивают в течение 5 секунд. Итак, да, потоки строго по требованию. Число может быть изменено с помощью
setThreads()
метода.Следит за тем, чтобы минимальное количество основных потоков никогда не было меньше единицы, иначе
submit()
будет отклонять каждую задачу. Поскольку основные потоки должны быть> = max потоков, метод такжеsetThreads()
устанавливает максимальное количество потоков, хотя настройка максимального потока бесполезна для неограниченной очереди.источник
В вашем первом примере последующие задачи отклоняются, потому что
AbortPolicy
по умолчаниюRejectedExecutionHandler
. ThreadPoolExecutor содержит следующие политики, которые вы можете изменить с помощьюsetRejectedExecutionHandler
метода:Похоже, вам нужен кешированный пул потоков с CallerRunsPolicy.
источник
Ни один из ответов здесь не устранил мою проблему, которая была связана с созданием ограниченного количества HTTP-соединений с использованием HTTP-клиента Apache (версия 3.x). Поскольку мне потребовалось несколько часов, чтобы найти хорошую настройку, я поделюсь:
Это создает объект,
ThreadPoolExecutor
который начинается с пяти и содержит максимум десять одновременно работающих потоков, используемыхCallerRunsPolicy
для выполнения.источник
Согласно Javadoc для ThreadPoolExecutor:
(Акцент мой.)
Ответ джиттера - это то, что вы хотите, хотя мой ответ на ваш другой вопрос. :)
источник
есть еще один вариант. Вместо использования новой SynchronousQueue вы также можете использовать любую другую очередь, но вы должны убедиться, что ее размер равен 1, так что это заставит Exectorservice создать новый поток.
источник
Не похоже, что какой-либо из ответов действительно отвечает на вопрос - на самом деле я не вижу способа сделать это - даже если вы подклассифицируете PooledExecutorService, поскольку многие из методов / свойств являются частными, например, создание addIfUnderMaximumPoolSize было защищено, вы могли сделать следующее:
Самое близкое, что я получил, было это - но даже это не очень хорошее решение
пс не проверял выше
источник
Вот еще одно решение. Я думаю, что это решение ведет себя так, как вы хотите (хотя и не горжусь этим решением):
источник
Это то, что вы хотите (по крайней мере, я так думаю). Для объяснения проверьте ответ Джонатана Файнберга
Executors.newFixedThreadPool(int n)
источник
Вы можете использовать,
ThreadPoolExecutor
как предлагает @sjleeВы можете управлять размером пула динамически. Взгляните на этот вопрос для получения более подробной информации:
Динамический пул потоков
ИЛИ
Вы можете использовать API newWorkStealingPool , который был представлен в java 8.
По умолчанию уровень параллелизма равен количеству ядер ЦП на вашем сервере. Если у вас есть сервер с 4-ядерным процессором, размер пула потоков будет равен 4. Этот API возвращает
ForkJoinPool
типExecutorService
и разрешает работу кражи незанятых потоков путем кражи задач из занятых потоков в ForkJoinPool.источник
Проблема была резюмирована следующим образом:
Прежде чем указать на решение, я объясню, почему следующие решения не работают:
Это не будет ставить в очередь задачи, когда будет достигнуто ограничение в 3, потому что SynchronousQueue, по определению, не может содержать никаких элементов.
Это не создаст более одного потока, потому что ThreadPoolExecutor создает потоки, превышающие corePoolSize, только если очередь заполнена. Но LinkedBlockingQueue никогда не бывает заполнен.
Это не будет повторно использовать потоки, пока не будет достигнут corePoolSize, потому что ThreadPoolExecutor увеличивает количество потоков до достижения corePoolSize, даже если существующие потоки простаивают. Если вы можете смириться с этим недостатком, то это самое простое решение проблемы. Это также решение, описанное в «Java Concurrency in Practice» (сноска на стр. 172).
Единственное полное решение описанной проблемы, по-видимому, связано с переопределением
offer
метода очереди и написанием,RejectedExecutionHandler
как описано в ответах на этот вопрос: как заставить ThreadPoolExecutor увеличить потоки до максимального значения перед постановкой в очередь?источник
Это работает для Java8 + (и других пока что ..)
где 3 - это предел количества потоков, а 5 - тайм-аут для незанятых потоков.
Если вы хотите проверить, работает ли он самостоятельно , вот код для выполнения работы:
вывод кода выше для меня
источник