如何等待多个线程来完成?

什么是等待所有线程进程完成的方法? 例如,假设我有:

public class DoSomethingInAThread implements Runnable{ public static void main(String[] args) { for (int n=0; n<1000; n++) { Thread t = new Thread(new DoSomethingInAThread()); t.start(); } // wait for all threads' run() methods to complete before continuing } public void run() { // do something here } } 

如何修改这个,使main()方法在注释中暂停,直到所有线程的run()方法退出? 谢谢!

你把所有线程放在一个数组中,全部启动,然后循环

 for(i = 0; i < threads.length; i++) threads[i].join(); 

每个连接都会阻塞,直到相应的线程完成。 线程可能以不同于join它们的顺序完成,但这不是问题:当循环退出时,所有线程都完成。

一种方法是创buildThread List ,创build并启动每个线程,同时将其添加到列表中。 一旦启动了所有内容,循环访问列表并在每个列表中调用join() 。 线程完成执行的顺序并不重要,所有你需要知道的是,当第二个循环完成时,每个线程都将完成。

更好的方法是使用ExecutorService及其关联的方法:

 List<Callable> callables = ... // assemble list of Callables here // Like Runnable but can return a value ExecutorService execSvc = Executors.newCachedThreadPool(); List<Future<?>> results = execSvc.invokeAll(callables); // Note: You may not care about the return values, in which case don't // bother saving them 

使用一个ExecutorService(以及所有来自Java 5 并发实用程序的新东西)非常灵活,上面的例子几乎没有改变。

 import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class DoSomethingInAThread implements Runnable { public static void main(String[] args) throws ExecutionException, InterruptedException { //limit the number of actual threads int poolSize = 10; ExecutorService service = Executors.newFixedThreadPool(poolSize); List<Future<Runnable>> futures = new ArrayList<Future<Runnable>>(); for (int n = 0; n < 1000; n++) { Future f = service.submit(new DoSomethingInAThread()); futures.add(f); } // wait for all tasks to complete before continuing for (Future<Runnable> f : futures) { f.get(); } //shut down the executor service so that this thread can exit service.shutdownNow(); } public void run() { // do something here } } 

避免使用Thread类,而是使用java.util.concurrent中提供的更高级的抽象

ExecutorService类提供的方法invokeAll似乎只是你想要的。

而不是join() ,这是一个旧的API,你可以使用CountDownLatch 。 我已经修改您的代码,如下所示,以满足您的要求。

 import java.util.concurrent.*; class DoSomethingInAThread implements Runnable{ CountDownLatch latch; public DoSomethingInAThread(CountDownLatch latch){ this.latch = latch; } public void run() { try{ System.out.println("Do some thing"); latch.countDown(); }catch(Exception err){ err.printStackTrace(); } } } public class CountDownLatchDemo { public static void main(String[] args) { try{ CountDownLatch latch = new CountDownLatch(1000); for (int n=0; n<1000; n++) { Thread t = new Thread(new DoSomethingInAThread(latch)); t.start(); } latch.await(); System.out.println("In Main thread after completion of 1000 threads"); }catch(Exception err){ err.printStackTrace(); } } } 

说明

  1. CountDownLatch已按照您的要求初始化为给定数量1000。

  2. 每个工作线程DoSomethingInAThread将递减在构造函数中传递的CountDownLatch

  3. 主线程CountDownLatchDemo await()直到计数变为零。 一旦计数变为零,您将在输出中获得下线。

     In Main thread after completion of 1000 threads 

从oracle文档页面获取更多信息

 public void await() throws InterruptedException 

导致当前线程一直等到锁存器计数到零,除非线程中断。

其他选项请参考相关的SE问题:

等到所有的线程在java中完成他们的工作

正如马丁Kbuild议java.util.concurrent.CountDownLatch似乎是一个更好的解决scheme。 只需添加一个相同的例子

  public class CountDownLatchDemo { public static void main (String[] args) { int noOfThreads = 5; // Declare the count down latch based on the number of threads you need // to wait on final CountDownLatch executionCompleted = new CountDownLatch(noOfThreads); for (int i = 0; i < noOfThreads; i++) { new Thread() { @Override public void run () { System.out.println("I am executed by :" + Thread.currentThread().getName()); try { // Dummy sleep Thread.sleep(3000); // One thread has completed its job executionCompleted.countDown(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); } try { // Wait till the count down latch opens.In the given case till five // times countDown method is invoked executionCompleted.await(); System.out.println("All over"); } catch (InterruptedException e) { e.printStackTrace(); } } } 

根据您的需要,您可能还想查看java.util.concurrent包中的CountDownLatch和CyclicBarrier类。 如果你想让你的线程相互等待,或者如果你想对线程执行的方式(例如,在内部执行中等待另一个线程设置某种状态)进行更细粒度的控制,它们可能会很有用。 您也可以使用CountDownLatch指示所有线程同时启动,而不是在迭代循环时逐个启动它们。 标准API文档有一个例子,再加上使用另一个CountDownLatch来等待所有的线程完成它们的执行。

考虑使用java.util.concurrent.CountDownLatch 。 在javadocs中的例子

如果你创build了一个线程列表,你可以遍历它们和.join(),每个线程都有一个循环。 我还没有尝试过。

http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#join();

这将是一个评论,但我不能做评论呢。

Martin K ,我很好奇你将如何使用ThreadGroup 。 你以前做过吗?

我在上面看到,你build议检查activeCount – 暂时搁置Martin v L?ws对于投票的担心,我还有一个关于activeCount本身的问题。

警告:我没有试过使用这个,所以我不是这方面的专家,但根据javadocs ,它返回活动线程的估计数。

就个人而言,我不愿意尝试build立一个估计系统。 你有没有想过如何去做,或者我误解了javadoc?

在第一个for循环中创build线程对象。

 for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(new Runnable() { public void run() { // some code to run in parallel } }); threads[i].start(); } 

那么这里的每个人都在说什么。

 for(i = 0; i < threads.length; i++) threads[i].join(); 

你可以用Object “ThreadGroup”和它的参数activeCount来做到这一点:

作为CountDownLatch的替代,你也可以使用CyclicBarrier

 public class ThreadWaitEx { static CyclicBarrier barrier = new CyclicBarrier(100, new Runnable(){ public void run(){ System.out.println("clean up job after all tasks are done."); } }); public static void main(String[] args) { for (int i = 0; i < 100; i++) { Thread t = new Thread(new MyCallable(barrier)); t.start(); } } } class MyCallable implements Runnable{ private CyclicBarrier b = null; public MyCallable(CyclicBarrier b){ this.b = b; } @Override public void run(){ try { //do something System.out.println(Thread.currentThread().getName()+" is waiting for barrier after completing his job."); b.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } 

在这种情况下使用CyclicBarrier barrier.await()应该是最后一个语句,即当你的线程完成它的工作。 CyclicBarrier可以使用reset()方法重新使用。 引用javadocs:

CyclicBarrier支持一个可选的Runnable命令,该命令在派对中的最后一个线程到达之后,但在任何线程被释放之前,每个障碍点运行一次。 在任何一方继续之前,这个屏障行动对于更新共享状态是有用的。