Ответ
Выбор зависит от уровня контроля и требований к управлению потоками.
Thread.start()
- Низкоуровневый API для прямого создания и запуска потока.
- Использовать: Для простых, единичных задач, где не требуется пул потоков.
- Недостатки: Создание нового потока — дорогая операция, нет встроенного управления жизненным циклом группы потоков.
Thread thread = new Thread(() -> { System.out.println("Выполняю задачу в отдельном потоке"); }); thread.start();
ExecutorService.submit()
- Высокоуровневый API для работы с пулами потоков (thread pools).
- Использовать: Практически всегда в production-коде для многозадачности.
- Преимущества:
- Переиспользование потоков: Снижение накладных расходов.
- Управление ресурсами: Ограничение количества одновременных задач.
- Возврат результата: Возвращает объект
Future<T>для получения результата или исключения. - Грамотное завершение: Методы
shutdown()/shutdownNow().
// Создание пула из 4 потоков
ExecutorService executor = Executors.newFixedThreadPool(4);
// Отправка задачи на выполнение
Future<Integer> future = executor.submit(() -> {
// Длительная операция
return 42;
});
// Получение результата (блокирующий вызов)
Integer result = future.get();
// Обязательно завершаем сервис
executor.shutdown();
Рекомендация: В современных приложениях предпочтительнее использовать ExecutorService и его реализации (ForkJoinPool, ScheduledThreadPoolExecutor), так как это обеспечивает лучшую производительность, управляемость и соответствует best practices.