← Назад к вопросам

Что возвращает 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.

Что возвращает ThreadPoolExecutor? | PrepBro