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"); } }

Источник

Java – Waiting for Running Threads to Finish

Java concurrency allows running multiple sub-tasks of a task in separate threads. Sometimes, it is necessary to wait until all the threads have finished their execution. In this tutorial, we will learn a few ways to make the current thread wait for the other threads to finish.

1. Using ExecutorService and Future.get()

Java ExecutorService (or ThreadPoolExecutor) helps execute Runnable or Callable tasks asynchronously. Its submit() method returns a Future object that we can use to cancel execution and/or wait for completion.

In following example, we have a demo Runnable task. Each task completes in a random time between 0 to 1 second.

public class DemoRunnable implements Runnable < private Integer jobNum; public DemoRunnable(Integer index) < this.jobNum = index; >@SneakyThrows @Override public void run() < Thread.sleep(new Random(0).nextLong(1000)); System.out.println("DemoRunnable completed for index : " + jobNum); >>

We are submitting 10 tasks to the executor service. And then, we invoke Future.get() method on each Future object as received after submitting the task to the executor. The Future.get() waits if necessary for the task to complete, and then retrieves its result.

ExecutorService executor = Executors.newFixedThreadPool(5); List> futures = new ArrayList<>(); for (int i = 1; i f = executor.submit(new DemoRunnable(i)); futures.add(f); > System.out.println("###### All tasks are submitted."); for (Future f : futures) < f.get(); >System.out.println("###### All tasks are completed.");
###### All tasks are submitted. DemoRunnable completed for index : 3 DemoRunnable completed for index : 4 DemoRunnable completed for index : 1 DemoRunnable completed for index : 5 DemoRunnable completed for index : 2 DemoRunnable completed for index : 6 DemoRunnable completed for index : 10 DemoRunnable completed for index : 7 DemoRunnable completed for index : 9 DemoRunnable completed for index : 8 ###### All tasks are completed.

Note that the wait may terminate earlier under the following conditions:

  • the task is cancelled
  • the task execution threw an exception
  • there is an InterruptedException i.e., current thread was interrupted while waiting.

In such a case, we should implement our own logic to handle the exception.

2. Using ExecutorService shutdown() and awaitTermination()

The awaitTermination() method blocks until all tasks have completed execution after a shutdown() request on the executor service. Similar to Future.get(), it can unblock earlier if the timeout occurs, or the current thread is interrupted.

The shutdown() method closes the executor so no new tasks can be submitted, but previously submitted tasks continue execution.

The following method has the complete logic of waiting for all tasks to finish in 1 minute. After that, the executor service will be shut down forcibly using shutdownNow() method.

void shutdownAndAwaitTermination(ExecutorService executorService) < executorService.shutdown(); try < if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) < executorService.shutdownNow(); >> catch (InterruptedException ie) < executorService.shutdownNow(); Thread.currentThread().interrupt(); >>

We can use this method as follows:

ExecutorService executor = Executors.newFixedThreadPool(5); for (int i = 1; i System.out.println("###### All tasks are submitted."); shutdownAndAwaitTermination(executor); System.out.println("###### All tasks are completed.");

3. Using ExecutorService invokeAll()

This approach can be seen as a combination of the previous two approaches. It accepts the tasks as a collection and returns a list of Future objects to retrieve output if necessary. Also, it uses the shutdown and awaits logic for waiting for the tasks to be complete.

In following example, we are using the DemoCallable class that is very similar to DemoRunnable, except it returns an Integer value.

ExecutorService executor = Executors.newFixedThreadPool(10); List tasks = Arrays.asList( new DemoCallable(1), new DemoCallable(2), new DemoCallable(3), new DemoCallable(4), new DemoCallable(5), new DemoCallable(6), new DemoCallable(7), new DemoCallable(8), new DemoCallable(9), new DemoCallable(10)); System.out.println("###### Submitting all tasks."); List> listOfFutures = executor.invokeAll(tasks); shutdownAndAwaitTermination(executor); System.out.println("###### All tasks are completed.");

Note that listOfFutures stores the task outputs in the same order in which we had submitted the tasks to the executor service.

for (Future f : listOfFutures) < System.out.print(f.get() + " "); //Prints 1 2 3 4 5 6 7 8 9 10 >

The CountDownLatch class enables a Java thread to wait until a collection of threads (latch is waiting for) to complete their tasks.

CountDownLatch works by having a counter initialized with a number of threads, which is decremented each time a thread completes its execution. When the count reaches zero, it means all threads have completed their execution, and the main thread waiting on the latch resumes the execution.

In the following example, the main thread is waiting for 3 given services to complete before reporting the final system status. We can read the whole example in CountDownLatch example.

CountDownLatch latch = new CountDownLatch(3); List services = new ArrayList<>(); services.add(new NetworkHealthChecker(latch)); services.add(new CacheHealthChecker(latch)); services.add(new DatabaseHealthChecker(latch)); Executor executor = Executors.newFixedThreadPool(services.size()); for(final BaseHealthChecker s : services) < executor.execute(s); >//Now wait till all health checks are complete latch.await();

In this tutorial, we learned to make an application thread wait for other threads to finish. We learned to use the ExecutorService methods and CountDownLatch class.

Источник

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.

Источник

Читайте также:  Html portfolio template code
Оцените статью