如何等待多个线程来完成?
什么是等待所有线程进程完成的方法? 例如,假设我有:
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(); } } }
说明 :
-
CountDownLatch
已按照您的要求初始化为给定数量1000。 -
每个工作线程
DoSomethingInAThread
将递减在构造函数中传递的CountDownLatch
。 -
主线程
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命令,该命令在派对中的最后一个线程到达之后,但在任何线程被释放之前,每个障碍点运行一次。 在任何一方继续之前,这个屏障行动对于更新共享状态是有用的。