Java как дождаться окончания потока

Как дождаться завершения нескольких потоков

Добрый день. Столкнулся с такой проблемой:
в методе main() создается n одинаковых потоков, каждый из которых обрабатывает по файлу. Каким образом можно реализовать функциональность, когда основной поток (main) ждет завершения ВСЕХ порожденных потоков и только потом продолжает работу. Причем ThreadGroup использовать нельзя (чем то не нравится она нашему quality manager’у).

Дождаться полного выполнения пула потоков
ExecutorService service = Executors.newFixedThreadPool(4); for (int i=0;i<=fileCount;i++).

Ожидание завершения потоков, ExecutorService
Правила так правила. import java.util.Arrays; import java.util.Random; import.

Запуск нескольких независимых потоков. Дождаться завершения всех (C++ 11)
Доброго времени суток. Подскажите, как запустить несколько независимых потоков, но дождаться, пока.

Правильно создать пул потоков, запустить эти потоки одновременно и дождаться их завершения
Добрый день! Подскажите пожалуйста, как правильно создать пул потоков, запустить эти потоки.

Вот набросал пример.
Возможно не самый изщный но работать будет.
Обрати внимание — в конце метода run каждого дочернего Thread должен быть [bold]notifyAll();[/bold]

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
import java.util.Random; public class ThreadTest { public static void main(String[] args) { int threadCount = 5; final Random rand = new Random(); // Thread [] threads = new Thread[threadCount]; // for (int i = 0; i  threadCount; i ++) { Thread nextThread = new Thread(new Runnable() { public void run() { // some actions .. // for example int sleepSeconds = rand.nextInt(5); try { Thread.sleep(sleepSeconds * 1000); } catch (InterruptedException e) { // do nothing } // Note! here thread will notify about finish of its work System.out.println(Thread.currentThread().getName() + " about to finish"); synchronized (this) { notifyAll(); } } }); // nextThread.setName("Thread_" + (i + 1)); threads[i] = nextThread; nextThread.start(); } // waiting while all threads alive for (int i = 0; i  threads.length; i++) { Thread nextThread = threads[i]; if (nextThread.isAlive()){ try { synchronized (nextThread) { nextThread.wait(); } } catch (InterruptedException e) { // do nothing } } } // continue System.out.println("Main thread continue work"); } }

Источник

ExecutorService — Ожидание завершения потоков

ФреймворкExecutorService упрощает обработку задач в нескольких потоках. Мы собираемся проиллюстрировать некоторые сценарии, в которых мы ждем, пока потоки завершат свое выполнение.

Кроме того, мы покажем, как корректно завершить работуExecutorService и дождаться, пока уже запущенные потоки завершат свое выполнение.

2. После выключенияExecutor’s

При использованииExecutor, мы можем выключить его, вызвав методыshutdown() илиshutdownNow(). Although, it won’t wait until all threads stop executing.

Ожидание завершения выполнения существующих потоков может быть достигнуто с помощью методаawaitTermination().

Это блокирует поток до тех пор, пока все задачи не завершат свое выполнение или не истечет указанное время ожидания:

public void awaitTerminationAfterShutdown(ExecutorService threadPool) < threadPool.shutdown(); try < if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) < threadPool.shutdownNow(); >> catch (InterruptedException ex) < threadPool.shutdownNow(); Thread.currentThread().interrupt(); >>

3. ИспользуяCountDownLatch

Затем давайте рассмотрим другой подход к решению этой проблемы — использованиеCountDownLatch для сигнализации о завершении задачи.

Мы можем инициализировать его значением, которое представляет, сколько раз он может быть уменьшен до того, как будут уведомлены все потоки, вызвавшие методawait().

Например, если нам нужно, чтобы текущий поток ожидал, пока другой потокN завершит свое выполнение, мы можем инициализировать защелку, используяN:

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10); CountDownLatch latch = new CountDownLatch(2); for (int i = 0; i < 2; i++) < WORKER_THREAD_POOL.submit(() -> < try < // . latch.countDown(); >catch (InterruptedException e) < Thread.currentThread().interrupt(); >>); > // wait for the latch to be decremented by the two remaining threads latch.await();

4. ИспользуяinvokeAll()

Первый подход, который мы можем использовать для запуска потоков, — это методinvokeAll(). The method returns a list of Future objects after all tasks finish or the timeout expires.

Также мы должны отметить, что порядок возвращаемых объектовFuture такой же, как и список предоставленных объектовCallable:

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10); List> callables = Arrays.asList( new DelayedCallable("fast thread", 100), new DelayedCallable("slow thread", 3000)); long startProcessingTime = System.currentTimeMillis(); List> futures = WORKER_THREAD_POOL.invokeAll(callables); awaitTerminationAfterShutdown(WORKER_THREAD_POOL); long totalProcessingTime = System.currentTimeMillis() - startProcessingTime; assertTrue(totalProcessingTime >= 3000); String firstThreadResponse = futures.get(0).get(); assertTrue("fast thread".equals(firstThreadResponse)); String secondThreadResponse = futures.get(1).get(); assertTrue("slow thread".equals(secondThreadResponse));

5. ИспользуяExecutorCompletionService

Другой подход к запуску нескольких потоков — использованиеExecutorCompletionService.. Он использует предоставленныйExecutorService для выполнения задач.

Одно отличие отinvokeAll() — это порядок, в котором возвращаютсяFutures,, представляющие выполненные задачи. ExecutorCompletionService uses a queue to store the results in the order they are finished, аinvokeAll() возвращает список, имеющий тот же последовательный порядок, что и созданный итератором для данного списка задач:

CompletionService service = new ExecutorCompletionService<>(WORKER_THREAD_POOL); List callables = Arrays.asList( new DelayedCallable("fast thread", 100), new DelayedCallable("slow thread", 3000)); for (Callable callable : callables)

Доступ к результатам можно получить с помощью методаtake():

long startProcessingTime = System.currentTimeMillis(); Future future = service.take(); String firstThreadResponse = future.get(); long totalProcessingTime = System.currentTimeMillis() - startProcessingTime; assertTrue("First response should be from the fast thread", "fast thread".equals(firstThreadResponse)); assertTrue(totalProcessingTime >= 100 && totalProcessingTime < 1000); LOG.debug("Thread finished after: " + totalProcessingTime + " milliseconds"); future = service.take(); String secondThreadResponse = future.get(); totalProcessingTime = System.currentTimeMillis() - startProcessingTime; assertTrue( "Last response should be from the slow thread", "slow thread".equals(secondThreadResponse)); assertTrue( totalProcessingTime >= 3000 && totalProcessingTime < 4000); LOG.debug("Thread finished after: " + totalProcessingTime + " milliseconds"); awaitTerminationAfterShutdown(WORKER_THREAD_POOL);

6. Заключение

В зависимости от варианта использования у нас есть различные варианты ожидания завершения потоков.

CountDownLatch полезен, когда нам нужен механизм для уведомления одного или нескольких потоков о завершении набора операций, выполняемых другими потоками.

ExecutorCompletionService полезен, когда нам нужно получить доступ к результату задачи как можно скорее, и другие подходы, когда мы хотим дождаться завершения всех запущенных задач.

Исходный код статьи доступенover on GitHub.

Источник

ExecutorService – Ожидание завершения потоков

Узнайте, как использовать ExecutorService в различных сценариях для ожидания завершения выполнения потоков.

1. Обзор

Платформа ExecutorService упрощает обработку задач в нескольких потоках. Мы приведем примеры некоторых сценариев, в которых мы ждем, пока потоки завершат свое выполнение.

Кроме того, мы покажем, как изящно завершить работу ExecutorService и дождаться завершения выполнения уже запущенных потоков.

2. После Завершения работы Исполнителя

При использовании исполнителя мы можем отключить его, вызвав методы shutdown () или shutdownNow () . Хотя он не будет ждать, пока все потоки перестанут выполняться.

Ожидание завершения выполнения существующих потоков может быть достигнуто с помощью Ожидание() метод.

Это блокирует поток до тех пор, пока все задачи не завершат свое выполнение или не будет достигнут указанный тайм-аут:

public void awaitTerminationAfterShutdown(ExecutorService threadPool) < threadPool.shutdown(); try < if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) < threadPool.shutdownNow(); >> catch (InterruptedException ex) < threadPool.shutdownNow(); Thread.currentThread().interrupt(); >>

3. Использование обратного отсчета

Далее давайте рассмотрим другой подход к решению этой проблемы – использование CountDownLatch для сигнала о завершении задачи.

Мы можем инициализировать его значением, представляющим количество раз, когда он может быть уменьшен, прежде чем все потоки, вызвавшие метод await () , будут уведомлены.

Например, если нам нужно, чтобы текущий поток ждал завершения выполнения другого потока N , мы можем инициализировать защелку с помощью N :

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10); CountDownLatch latch = new CountDownLatch(2); for (int i = 0; i < 2; i++) < WORKER_THREAD_POOL.submit(() -> < try < // . latch.countDown(); >catch (InterruptedException e) < Thread.currentThread().interrupt(); >>); > // wait for the latch to be decremented by the two remaining threads latch.await();

4. Использование invokeAll()

Первый подход, который мы можем использовать для запуска потоков, – это метод invokeAll () . Метод возвращает список Будущих объектов после завершения всех задач или истечения времени ожидания .

Кроме того, мы должны отметить, что порядок возвращаемых Будущих объектов совпадает со списком предоставленных Вызываемых объектов:

ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10); List> callables = Arrays.asList( new DelayedCallable("fast thread", 100), new DelayedCallable("slow thread", 3000)); long startProcessingTime = System.currentTimeMillis(); List> futures = WORKER_THREAD_POOL.invokeAll(callables); awaitTerminationAfterShutdown(WORKER_THREAD_POOL); long totalProcessingTime = System.currentTimeMillis() - startProcessingTime; assertTrue(totalProcessingTime >= 3000); String firstThreadResponse = futures.get(0).get(); assertTrue("fast thread".equals(firstThreadResponse)); String secondThreadResponse = futures.get(1).get(); assertTrue("slow thread".equals(secondThreadResponse));

5. Использование ExecutorCompletionService

Другой подход к запуску нескольких потоков заключается в использовании ExecutorCompletionService. Он использует предоставленный ExecutorService для выполнения задач.

Одним из отличий от invokeAll() является порядок, в котором возвращаются фьючерсы, представляющие выполненные задачи. ExecutorCompletionService использует очередь для хранения результатов в порядке их завершения , в то время как invokeAll() возвращает список, имеющий тот же последовательный порядок, что и созданный итератором для данного списка задач:

CompletionService service = new ExecutorCompletionService<>(WORKER_THREAD_POOL); List callables = Arrays.asList( new DelayedCallable("fast thread", 100), new DelayedCallable("slow thread", 3000)); for (Callable callable : callables)

Доступ к результатам можно получить с помощью метода take() :

long startProcessingTime = System.currentTimeMillis(); Future future = service.take(); String firstThreadResponse = future.get(); long totalProcessingTime = System.currentTimeMillis() - startProcessingTime; assertTrue("First response should be from the fast thread", "fast thread".equals(firstThreadResponse)); assertTrue(totalProcessingTime >= 100 && totalProcessingTime < 1000); LOG.debug("Thread finished after: " + totalProcessingTime + " milliseconds"); future = service.take(); String secondThreadResponse = future.get(); totalProcessingTime = System.currentTimeMillis() - startProcessingTime; assertTrue( "Last response should be from the slow thread", "slow thread".equals(secondThreadResponse)); assertTrue( totalProcessingTime >= 3000 && totalProcessingTime < 4000); LOG.debug("Thread finished after: " + totalProcessingTime + " milliseconds"); awaitTerminationAfterShutdown(WORKER_THREAD_POOL);

6. Заключение

В зависимости от варианта использования у нас есть различные варианты ожидания завершения выполнения потоков.

A Обратный отсчет полезно, когда нам нужен механизм для уведомления одного или нескольких потоков о завершении набора операций, выполняемых другими потоками.

ExecutorCompletionService это полезно, когда нам нужно как можно скорее получить доступ к результату задачи и другим подходам, когда мы хотим дождаться завершения всех запущенных задач.

Исходный код статьи доступен на GitHub .

Источник

Читайте также:  Currenttimemillis java в секундах
Оцените статью