Не используйте потоки напрямую, используйте платформу executor.
В частности, используйте CompletionService
, чтобы вы могли извлекать задачи, которые вы отправляете исполнителю, в порядке выполнения (успешно или нет).
Вместо:
Thread t1 = new Thread(() -> { /* runnable 1 */ });
Thread t2 = new Thread(() -> { /* runnable 2 */ });
Thread t3 = new Thread(() -> { /* runnable 3 */ });
Создайте CompletionService
:
ExecutorService executor = ...; // e.g. Executors.newFixedThreadPool
CompletionService completionService = new CompletionService(executor);
Теперь создайте список для хранения Future
s, возвращаемых отправкой задач.CompletionService
:
List<Future<?>> futures = new ArrayList<>();
futures.add(completionService.submit(() -> { /* runnable 1 */ }));
futures.add(completionService.submit(() -> { /* runnable 2 */ }));
futures.add(completionService.submit(() -> { /* runnable 3 */ }));
Теперь используйте take
, чтобы получить фьючерсы в порядке завершения:
for (int i = 0; i < futures.size(); ++i) {
Future<?> completed = futures.take();
try {
completed.get();
} catch (ExecutionException e) {
// An exception occurred whilst running the task.
// Cancel all the tasks.
futures.forEach(f -> f.cancel(true));
}
}
Конечно, cancel
может что-либо сделатьздесь полезно, вам понадобятся ваши runnables для проверки на прерывание;но в любом случае вам понадобятся средства для проверки «сбоя» в других потоках.