Ответ
Пул потоков (Thread Pool) — это набор предсозданных потоков, готовых к выполнению задач. Вместо создания нового потока для каждой задачи, пул переиспользует существующие, что снижает накладные расходы и упрощает управление параллелизмом.
Основной интерфейс — ExecutorService.
Пример создания через Executors:
// 1. Фиксированный пул
ExecutorService fixedPool = Executors.newFixedThreadPool(4);
// 2. Кэширующий пул (создаёт потоки по мере необходимости)
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 3. Пул с одним потоком (последовательное выполнение)
ExecutorService singleThread = Executors.newSingleThreadExecutor();
// 4. Отправка задачи в пул
fixedPool.submit(() -> {
System.out.println("Задача выполняется в " + Thread.currentThread().getName());
});
// 5. Корректное завершение работы пула
fixedPool.shutdown(); // Остановка после выполнения всех задач
// fixedPool.shutdownNow(); // Попытка немедленной остановки
Прямое создание ThreadPoolExecutor (больше контроля):
int corePoolSize = 5;
int maxPoolSize = 10;
long keepAliveTime = 60L;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
workQueue
);
Преимущества:
- Снижение затрат на создание/уничтожение потоков.
- Ограничение количества одновременно работающих потоков.
- Управление очередью задач.
Важные моменты:
- Всегда завершайте пул (
shutdown()). - Выбор типа пула и его параметров зависит от характера задач (CPU-bound, I/O-bound).
- Используйте
ThreadFactoryдля настройки создаваемых потоков (имена, приоритеты, демоны).
Ответ 18+ 🔞
А, ну это же классика, блядь! Пул потоков! Ну ты представляешь, каждый раз, когда тебе надо задачу выполнить, новый поток создавать — это как, сука, каждый раз новую тарелку брать, поел — в окно выкинул. Овердохуища мусора будет, а потом прибежит сборщик и наебнёт тебе по голове за такое расточительство.
Вот поэтому умные дядьки придумали, блядь, Thread Pool — это типа такая бригада предсозданных работяг-потоков. Сидят, блядь, на базе, курят, ждут заданий. Кинул им задачку — один отрывает жопу от стула, пошёл делать. Сделал — вернулся, опять сел ждать. Красота, а не жизнь! Накладных расходов — ноль ебать, управлять — одно удовольствие.
Главный по тарелкам тут — ExecutorService. Через него всё и делается.
Смотри, как это выглядит в коде, ёпта:
// 1. Пул фиксированный, чтоб не разбегались
ExecutorService fixedPool = Executors.newFixedThreadPool(4); // Четыре работяги, ни больше, ни меньше.
// 2. Пул кэширующий — ленивые понты. Пока задач нет — ни одного потока. Задачу кинул — поток создался. Сделал — если минуту прохлаждался, убили нахуй.
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 3. Пул с одним дауном. Один поток, всё делает по очереди, строго. Для тех, кто боится параллелизма как чёрт ладана.
ExecutorService singleThread = Executors.newSingleThreadExecutor();
// 4. А вот как кинуть задачку этим лентяям:
fixedPool.submit(() -> {
System.out.println("Задача выполняется в " + Thread.currentThread().getName()); // Смотри, какой Вася её сделал!
});
// 5. И ВАЖНО, БЛЯДЬ! После работы бригаду распустить, а то они вечно сидеть будут, ресурсы жрать!
fixedPool.shutdown(); // Вежливо: "Ребят, новых заданий не будет, доделывайте что есть и свободны!"
// fixedPool.shutdownNow(); // Жёстко: "Всё, пиздуйте отсюда по-хорошему! А то щас по мордам дам!"
Но если ты, блядь, максималист и хочешь всё контролировать до запятой — можешь собрать пул своими руками, как конструктор:
int corePoolSize = 5; // Постоянный штат: 5 человек всегда на базе, даже если нихуя не делают.
int maxPoolSize = 10; // Максимальная численность: если завал, нанимаем временщиков, чтоб до 10 человек.
long keepAliveTime = 60L; // Временщик, если 60 секунд без дела просидел — увольнение, нахуй.
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100); // Очередь задач на 100 штук. Переполнится — проблемы.
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
workQueue
);
Чем это, сука, хорошо?
- Не тратишь время на найм и увольнение (создание/уничтожение потоков).
- Можешь поставить лимит на дебоширов (ограничить число потоков).
- Все задачи в одну аккуратную очередь становятся, а не кто в лес, кто по дрова.
Но запомни, чувак:
- Всегда
shutdown()вызывай, иначе память течь будет — пипец. - Выбирай пул с умом: для задач, где мозги пашут (CPU-bound) — фиксированный небольшой, для задач, где много ждёшь (I/O-bound) — можно и кэширующий.
- Хочешь, чтобы твои потоки не безликими были — юзай
ThreadFactory. Задашь им имена, приоритеты, сделаешь демонами — полный контроль, блядь!