Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
FixedThreadPool: пул потоков с фиксированным размером
FixedThreadPool — это реализация ExecutorService из пакета java.util.concurrent, которая создаёт пул с фиксированным числом рабочих потоков. Это один из самых популярных и простых способов управления многопоточностью в Java.
Основная концепция
FixedThreadPool содержит определённое количество потоков, которые переиспользуются для выполнения задач:
// Создание FixedThreadPool на 5 потоков
ExecutorService executor = Executors.newFixedThreadPool(5);
// Теперь этот пул будет содержать ровно 5 потоков
// Все задачи выполняются этими 5 потоками
Как это работает
public class FixedThreadPoolExample {
public static void main(String[] args) {
// Создаём пул из 3 потоков
ExecutorService executor = Executors.newFixedThreadPool(3);
// Отправляем 10 задач
for (int i = 1; i <= 10; i++) {
final int taskNumber = i;
executor.submit(() -> {
System.out.println("Task " + taskNumber + " started by " +
Thread.currentThread().getName());
try {
Thread.sleep(1000); // Имитируем работу
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Task " + taskNumber + " finished");
});
}
// Вывод будет примерно:
// Task 1 started by pool-1-thread-1
// Task 2 started by pool-1-thread-2
// Task 3 started by pool-1-thread-3
// (остальные 7 задач ждут в очереди)
// Task 4 started by pool-1-thread-1 (когда thread-1 закончила)
executor.shutdown(); // Корректно завершаем пул
}
}
Внутренняя структура
// Упрощённая реализация FixedThreadPool
public class SimplifiedFixedThreadPool {
private final ExecutorService executor = Executors.newFixedThreadPool(3);
// Внутри:
// - ThreadPoolExecutor с: corePoolSize = 3, maxPoolSize = 3
// - LinkedBlockingQueue для хранения задач
// - 3 рабочих потока, которые берут задачи из очереди
}
Основные параметры:
- corePoolSize = количество потоков (например, 5)
- maxPoolSize = максимум потоков (также 5 для FixedThreadPool)
- queue = LinkedBlockingQueue (неограниченная очередь)
Практический пример: обработка запросов
public class RequestProcessor {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
private final List<String> results = Collections.synchronizedList(new ArrayList<>());
public void processRequests(List<String> requests) {
for (String request : requests) {
executor.submit(() -> {
String result = handleRequest(request);
results.add(result);
});
}
}
private String handleRequest(String request) {
// Обработка запроса (может быть медленной)
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Processed: " + request;
}
public void waitForCompletion() throws InterruptedException {
executor.shutdown();
if (!executor.awaitTermination(5, TimeUnit.MINUTES)) {
executor.shutdownNow();
}
}
}
Разница между execute и submit
public class ExecuteVsSubmit {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(2);
// execute(Runnable) - не возвращает результат
executor.execute(() -> System.out.println("Runnable task"));
// submit(Runnable) - возвращает Future<Void>
Future<Void> future1 = executor.submit(() -> System.out.println("Submit runnable"));
future1.get(); // Ждём завершения
// submit(Callable<T>) - возвращает Future<T>
Future<String> future2 = executor.submit(() -> "Result");
String result = future2.get(); // Получаем результат
System.out.println(result);
executor.shutdown();
}
}
Корректное завершение пула
public class ProperShutdown {
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(3);
// Отправляем задачи
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
System.out.println(Thread.currentThread().getName());
});
}
// Способ 1: Graceful shutdown
executor.shutdown(); // Не принимает новые задачи, ждёт окончания
// Ждём максимум 10 секунд
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
// Если не закончилось за 10 сек
List<Runnable> pendingTasks = executor.shutdownNow(); // Прерываем
System.out.println("Pending tasks: " + pendingTasks.size());
}
System.out.println("Executor terminated");
}
}
Сравнение типов пулов
public class ThreadPoolComparison {
public static void main(String[] args) {
// 1. FixedThreadPool - фиксированное количество потоков
ExecutorService fixed = Executors.newFixedThreadPool(5);
// Хорошо для: predictable workload, ограниченные ресурсы
// 2. CachedThreadPool - динамичное количество
ExecutorService cached = Executors.newCachedThreadPool();
// Хорошо для: много коротких задач, переменная нагрузка
// 3. SingleThreadExecutor - один поток
ExecutorService single = Executors.newSingleThreadExecutor();
// Хорошо для: последовательные задачи, гарантия порядка
// 4. ScheduledThreadPool - для периодических задач
ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(5);
// Хорошо для: задачи по расписанию
}
}
Когда использовать FixedThreadPool
// ✓ ХОРОШО: обработка HTTP запросов на веб-сервере
public class WebServer {
private final ExecutorService executor = Executors.newFixedThreadPool(100);
public void handleRequest(HttpRequest request) {
executor.submit(() -> {
// Обработка запроса в отдельном потоке
processRequest(request);
});
}
}
// ✓ ХОРОШО: обработка задач из очереди
public class TaskProcessor {
private final ExecutorService executor = Executors.newFixedThreadPool(5);
public void processTasksFromQueue(Queue<Task> taskQueue) {
while (!taskQueue.isEmpty()) {
Task task = taskQueue.poll();
executor.submit(() -> task.execute());
}
}
}
// ❌ ПЛОХО: очень много задач одновременно
ExecutorService executor = Executors.newFixedThreadPool(1000000); // Память!
// ❌ ПЛОХО: если нужна гибкость размера
// Используй ScheduledThreadPool или CachedThreadPool
Memory Usage
public class MemoryExample {
public static void main(String[] args) throws InterruptedException {
// FixedThreadPool с 1000 потоков
ExecutorService executor = Executors.newFixedThreadPool(1000);
// Каждый поток занимает ~1MB памяти (stack)
// Итого: ~1GB памяти только на потоки!
// Поэтому:
// - Маленькие пулы (10-20) для обработки запросов
// - Большие пулы (100+) только для специфических случаев
executor.shutdown();
}
}
Best Practices
public class BestPractices {
// 1. Размер пула зависит от нагрузки
// Для I/O-bound: pool_size = 2 * number_of_cpus
// Для CPU-bound: pool_size = number_of_cpus
private static final int OPTIMAL_POOL_SIZE =
Runtime.getRuntime().availableProcessors() * 2;
private final ExecutorService executor =
Executors.newFixedThreadPool(OPTIMAL_POOL_SIZE);
// 2. Обрабатывай исключения
public void submitTask() {
executor.submit(() -> {
try {
doWork();
} catch (Exception e) {
logger.error("Task failed", e);
}
});
}
// 3. Корректно завершай
public void shutdown() throws InterruptedException {
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);
}
}
FixedThreadPool — один из самых полезных инструментов для управления многопоточностью в Java, особенно в приложениях, обрабатывающих запросы.