Введение
Между потоками Java и потоками операционной системы существует взаимно однозначное соответствие.,Каждый раз, когда создается объект потока Java, операционная система будет отвечать за создание соответствующего системного потока.。Потоки — это ценные ресурсы операционной системы. Создание и уничтожение очень дороги и неэффективны.。(в настоящий моментJDK19Уже появилсяВиртуальный поток-Виртуальный Threads предварительная версия )。
Чтобы улучшить производительность и облегчить управление потоками,В разработке,Мы обычноОговорено, что должен использоваться пул потоков, и вам не разрешено создавать потоки вручную.。
В сценарии микросервиса используйте пул потоковчас,Чтобы избежать потери информации об отслеживании ссылок,долженИспользуйте пул потоков, инкапсулированный с информацией о ссылках, например TraceableExecutorService, в среде Spring Cloud.。
[Следите за общедоступным аккаунтом: Техническая группа когнитивных технологий]
7 основных параметров и анализ пула потоков ThreadPoolTaskExecutor
Создайте конструктор, содержащий 7 основных параметров для пула потоков [необходимо использовать]:
[Следите за общедоступным аккаунтом: Техническая группа когнитивных технологий]
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
1. Количество основных потоков (corePoolSize) и максимальное количество потоков (maximumPoolSize).
Пул потоков автоматически поддерживает количество рабочих потоков в пуле потоков на основе значений corePoolSize и MaximumPoolSize. Общие правила следующие:
(1)кпул Когда поток отправляет задачу, если текущий пул потоковсередина Работа Количество потоковменьше, чем corePoolSize, для выполнения задачи будет создан новый поток, даже если другие рабочие потоки в пуле потоков простаивают.。
Если основные потоки созданы заранее: prestartAllCoreThreads:
java.util.concurrent.ThreadPoolExecutor#prestartCoreThread
java.util.concurrent.ThreadPoolExecutor#prestartAllCoreThreads
Затем перейдите непосредственно к шагу (2).
(2)кпул Когда поток отправляет задачу, если текущий пул потоковсередина Работа Количество потоковЕсли значение больше, чем corePoolSize, но меньше, чем MaximumPoolSize, новый поток будет создан для выполнения задачи только тогда, когда рабочая очередь задач workQueue заполнена.。
(3) Значения corePoolSize и MaximumPoolSize можно указывать не только в конструкторе.,иПоддержка динамической настройки среды выполнения пула потоков.。
java.util.concurrent.ThreadPoolExecutor#setCorePoolSize
java.util.concurrent.ThreadPoolExecutor#setMaximumPoolSize
2. KeepAliveTime и единица измерения, время политики повторного использования простоя потока
По умолчанию,неосновные потокиОпределенно бесплатночас По истечении времени,Его необходимо выпустить и переработать,Это свободное времячас Пространство состоит изKeepAliveTime и единица измерения определяются совместно:
this.keepAliveTime = unit.toNanos(keepAliveTime);
Мы также можем динамически устанавливать значения в зависимости от условий задачи:
java.util.concurrent.ThreadPoolExecutor#setKeepAliveTime
Политика переработки простаивающих потоков по умолчанию предназначена только для неосновных потоков. Если вы хотите применить ее к основным потокам, мы должны отобразить настройки:
java.util.concurrent.ThreadPoolExecutor#allowsCoreThreadTimeOut
Когда рабочие потоки в пуле потоков запускаются,
java.util.concurrent.ThreadPoolExecutor.Worker#run
Этот рабочий поток работает до тех пор, пока первая задача или задача может быть получена из очереди задач. KeepAliveTime в основном используется для получения головной задачи из тайм-аута блокировки очереди задач.
Если этот рабочий поток простаивает в течение KeepAliveTime, то есть очередь задач блокирует тайм-аут KeepAliveTime для получения задачи руководителя группы. Когда задача не может быть получена, устанавливается флаг тайм-аута. В следующий раз цикл for оценивается в соответствии с. в соответствии с политикой тайм-аута, следует ли войти в цикл for, чтобы снова получить задачу из очереди задач, или NULL возвращается после тайм-аута, что приводит к завершению рабочего потока и его повторному использованию.
3. workQueue, очередь задач
Основная функция очереди задач workQueue — кэширование отправленных задач. Когда количество потоков пула потоков превышает количество неосновных потоков и не превышает максимальное количество потоков, отправленные задачи кэшируются в этой очереди задач. Потоки в пуле потоков всегда будут использовать задачи из этой очереди задач.
Избегайте ловушек: рекомендуется использовать очередь задач с ограниченной емкостью, чтобы накопление задач не приводило к возникновению OOM.
4. Фабрика потоков threadFactory
Главное задать имя треда при создании треда.、атрибут демона、Приоритет и другие атрибуты。Хорошие имена потоков можно использовать для анализа и решения проблем с помощью команды jstack.。
Реализация по умолчанию java.util.concurrent.Executors.DefaultThreadFactory:
Рекомендуется использовать org.apache.commons.lang3.concurrent.BasicThreadFactory.Builder:
BasicThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern("поток когнитивных технологий-%d")
.daemon(true)
.priority(Thread.MAX_PRIORITY)
.build();
5. Стратегия отклонения задач пула потоков-обработчиков
При отправке задачи в пул потоков текущее количество потоков превышает максимальное количество потоков MaximumPoolSize. В это время основные потоки заняты, очередь задач заполнена, и отправленная задача будет отклонена. Конечно, если пул потоков отключается, отправка также будет отклонена.。
JUC предоставляет несколько реализаций по умолчанию:
(1)ThreadPoolExecutor.AbortPolicy
Если пул потоков не устанавливает политику отклонения задач, политикой по умолчанию является AbortPolicy, выдавая исключение:
RejectedExecutionException отклоняет отправку задачи.
(2)ThreadPoolExecutor.CallerRunsPolicy
Если поток, отправивший задачу, выполняет задачу, то есть поток, который в данный момент отправляет задачу, непосредственно выполняет задачу, вызывая Runnable.run(), который заблокирует текущий поток.
Как правило, при использовании этой стратегии журналы следует распечатывать и сообщать о них.
new ThreadPoolExecutor.CallerRunsPolicy() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
log.info("rejectedExecution ");
super.rejectedExecution(r, e);
}
}
Общий сценарий использования: замена последовательных вызовов на параллельные вызовы, чтобы настройки пула потоков не были недостаточными и не переросли в последовательные вызовы. Когда задача отклоняется, размер пула потоков динамически корректируется для поиска подходящих параметров.
(3)ThreadPoolExecutor.DiscardPolicy
Отклоненные задачи молча отбрасываются, ничего не делается и даже лог не печатается.
Эта политика запрещена во время разработки.
Если вы вернете Future после отправки задачи в пул потоков и используете метод get без таймаута для получения результата, вас могут заблокировать навсегда.
Избегайте ловушек Цуй Жижи,Официальный аккаунт:Техническая команда когнитивных технологийПараллелизм Java: как FutureTask выполняет многопоточное одновременное выполнение и асинхронное получение результатов задач? И как избежать подводных камней
(4)ThreadPoolExecutor.DiscardOldestPolicy
Очередь потерянных задач отбрасывает головную задачу и пытается снова отправить задачу в пул потоков.
Эта стратегия не рекомендуется.
Чтобы реализовать политику отклонения задач вышеуказанного пула потоков, нам обычно необходимо наследовать ее и добавить операцию печати журнала.
Отправьте задачу в процесс пула потоков ThreadPoolTaskExecutor.
Как показано ниже:
(1) При отправке задачи в пул потоков, если количество рабочих потоков в текущем пуле потоков меньше, чем corePoolSize, будет создан новый поток для выполнения задачи, даже если другие рабочие потоки в пуле потоков простаивают. .
(2) Если при отправке задачи в пул потоков количество рабочих потоков в текущем пуле потоков превышает corePoolSize, текущая задача сохраняется в рабочей очереди задач workQueue.
(3) При отправке задачи в пул потоков, если количество рабочих потоков в текущем пуле потоков больше, чем corePoolSize, но меньше, чем MaximumPoolSize, а рабочая очередь задачи workQueue заполнена, создается новый поток для выполнения задачи. .
(4) При отправке задачи в пул потоков, если количество рабочих потоков в текущем пуле потоков превышает corePoolSize, а рабочая очередь задачи workQueue заполнена, а количество рабочих потоков в текущем пуле потоков больше чем MaximumPoolSize, будет выполнена политика отклонения задачи, чтобы отклонить отправку задачи.
пул потоковThreadPoolTaskExecutorИзбегайте ловушек