← Назад к вопросам
Что возвращает ThreadPoolExecutor?
1.0 Junior🔥 201 комментариев
#ORM и Hibernate#Spring Boot и Spring Data#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что возвращает ThreadPoolExecutor
Токен вопроса требует понимания разницы между различными методами ExecutorService и ThreadPoolExecutor. Разберу подробно что каждый метод возвращает.
ThreadPoolExecutor и его методы
ThreadPoolExecutor наследует AbstractExecutorService который наследует ExecutorService. Это основной класс для управления потоками.
public class ThreadPoolExecutor extends AbstractExecutorService {
// Основные методы
void execute(Runnable command)
<T> Future<T> submit(Callable<T> task)
<T> Future<T> submit(Runnable task, T result)
Future<?> submit(Runnable task)
// ...
}
execute() — Runnable, ничего не возвращает
ExecutorService executor = Executors.newFixedThreadPool(2);
// execute() принимает Runnable и НИЧЕГО не возвращает
executor.execute(() -> {
System.out.println("Task executed");
});
// void — результата нет
Когда использовать execute():
- Когда не нужен результат
- Когда не нужно ждать завершения
- Fire and forget операции
submit(Callable<T>) — возвращает Future<T>
ExecutorService executor = Executors.newFixedThreadPool(2);
// submit() с Callable возвращает Future
Future<String> future = executor.submit(() -> {
Thread.sleep(1000);
return "Task completed with result";
});
// Получить результат
String result = future.get(); // Блокирует до получения результата
System.out.println(result); // "Task completed with result"
Future<T> позволяет:
// 1. Получить результат
T result = future.get();
// 2. Получить результат с timeout
T result = future.get(5, TimeUnit.SECONDS);
// 3. Проверить готовность
if (future.isDone()) {
System.out.println("Task completed");
}
// 4. Проверить отмену
if (future.isCancelled()) {
System.out.println("Task cancelled");
}
// 5. Отменить задачу
future.cancel(true); // true = interrupt if running
submit(Runnable) — возвращает Future<?>
ExecutorService executor = Executors.newFixedThreadPool(2);
// submit() с Runnable возвращает Future<?>
Future<?> future = executor.submit(() -> {
System.out.println("Task running");
// Runnable ничего не возвращает
});
// Получить результат
Object result = future.get(); // null (Runnable ничего не возвращает)
Future<?> когда результата нет:
Это всё ещё полезно:
Future<?> future = executor.submit(runnableTask);
// Ждём завершения
future.get();
System.out.println("Task completed");
// Или с timeout
try {
future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("Task not completed in 5 seconds");
}
submit(Runnable, T result) — возвращает Future<T>
ExecutorService executor = Executors.newFixedThreadPool(2);
// submit() с Runnable и результатом возвращает Future<T>
Future<String> future = executor.submit(() -> {
System.out.println("Downloading file...");
// Runnable ничего не возвращает
}, "file.txt"); // Это результат
// Результат всегда будет "file.txt"
String result = future.get();
System.out.println(result); // "file.txt"
Когда использовать:
- Когда нужно дождаться завершения Runnable
- Когда результат известен заранее
Практическое сравнение
ExecutorService executor = Executors.newFixedThreadPool(3);
// Пример 1: execute() — fire and forget
executor.execute(() -> {
System.out.println("Background task");
});
// Программа продолжает работать, не ждёт результата
// Пример 2: submit(Callable) — нужен результат
Future<Integer> future = executor.submit(() -> {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum;
});
int result = future.get(); // Ждём результат
System.out.println("Sum: " + result);
// Пример 3: submit(Runnable) — нужно дождаться
Future<?> future2 = executor.submit(() -> {
System.out.println("Processing...");
Thread.sleep(2000);
System.out.println("Done");
});
future2.get(); // Ждём завершения
System.out.println("All finished");
ExecutorService.invokeAll() — возвращает List<Future<T>>
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Callable<Integer>> tasks = Arrays.asList(
() -> { Thread.sleep(100); return 1; },
() -> { Thread.sleep(200); return 2; },
() -> { Thread.sleep(150); return 3; }
);
// invokeAll() возвращает List<Future<T>>
List<Future<Integer>> futures = executor.invokeAll(tasks);
// Все задачи выполнены (или timeout)
for (Future<Integer> future : futures) {
System.out.println(future.get());
}
ExecutorService.invokeAny() — возвращает T
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Callable<String>> tasks = Arrays.asList(
() -> { Thread.sleep(1000); return "Task 1"; },
() -> { Thread.sleep(200); return "Task 2"; },
() -> { Thread.sleep(500); return "Task 3"; }
);
// invokeAny() возвращает результат ПЕРВОЙ УСПЕШНОЙ задачи
String result = executor.invokeAny(tasks);
System.out.println(result); // "Task 2" (самая быстрая)
Полная таблица
┌─────────────────────────────────────┬────────────────────┐
│ Метод │ Возвращает │
├─────────────────────────────────────┼────────────────────┤
│ execute(Runnable) │ void │
│ submit(Callable<T>) │ Future<T> │
│ submit(Runnable) │ Future<?> │
│ submit(Runnable, T) │ Future<T> │
│ invokeAll(List<Callable<T>>) │ List<Future<T>> │
│ invokeAny(List<Callable<T>>) │ T │
└─────────────────────────────────────┴────────────────────┘
Практический пример: обработка множества файлов
public class FileProcessor {
private ExecutorService executor = Executors.newFixedThreadPool(5);
// 1. Если просто нужно обработать (execute)
public void processFilesAsync(List<String> files) {
for (String file : files) {
executor.execute(() -> processFile(file));
}
// Главная программа продолжает работу
}
// 2. Если нужна обработка с контролем (submit + Future)
public List<ProcessResult> processFilesWithResults(
List<String> files) throws InterruptedException {
List<Future<ProcessResult>> futures = new ArrayList<>();
for (String file : files) {
Future<ProcessResult> future = executor.submit(
() -> processFileAndReturn(file)
);
futures.add(future);
}
// Собираем результаты
List<ProcessResult> results = new ArrayList<>();
for (Future<ProcessResult> future : futures) {
results.add(future.get()); // Ждём каждого
}
return results;
}
// 3. Если нужно дождаться всех (invokeAll)
public List<ProcessResult> processFilesAndWait(
List<String> files) throws InterruptedException {
List<Callable<ProcessResult>> tasks = files.stream()
.map(file -> (Callable<ProcessResult>)
() -> processFileAndReturn(file))
.collect(Collectors.toList());
List<Future<ProcessResult>> futures = executor.invokeAll(tasks);
// Все гарантированно завершены
return futures.stream()
.map(f -> {
try {
return f.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
}
// 4. Если нужен результат ПЕРВОГО (invokeAny)
public ProcessResult processFilesAny(
List<String> files) throws InterruptedException,
ExecutionException {
List<Callable<ProcessResult>> tasks = files.stream()
.map(file -> (Callable<ProcessResult>)
() -> processFileAndReturn(file))
.collect(Collectors.toList());
return executor.invokeAny(tasks);
}
private void processFile(String file) {
System.out.println("Processing " + file);
}
private ProcessResult processFileAndReturn(String file) {
return new ProcessResult(file, "processed");
}
}
Обработка ошибок при работе с Future
Future<Integer> future = executor.submit(() -> {
if (Math.random() > 0.5) {
throw new RuntimeException("Error occurred");
}
return 42;
});
try {
Integer result = future.get();
System.out.println("Result: " + result);
} catch (ExecutionException e) {
// Исключение выброшено в задаче
System.out.println("Task failed: " + e.getCause());
} catch (InterruptedException e) {
// Текущий поток был прерван
System.out.println("Thread interrupted");
}
Итог
ThreadPoolExecutor возвращает:
- execute() → void (ничего)
- submit(Callable) → Future<T> (результат задачи)
- submit(Runnable) → Future<?> (подтверждение выполнения)
- submit(Runnable, T) → Future<T> (заданный результат)
- invokeAll() → List<Future<T>> (все результаты)
- invokeAny() → T (результат первой задачи)
Знание этих различий критично для правильного использования многопоточности в Java.