Java:多线程等待所有线程结束(CountDownLatch/CyclicBarrier) .

本文主要是参考官方文档做一学习用途。

官方链接:

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CyclicBarrier.html 

多线程设计过程中,经常会遇到需要等待其它线程结束以后再做其他事情的情况,比如多线程下载文件,每个线程都会下载文件的一部分,在所有线程结束以后,需要将各部分再次拼接成一个完整的文件。

有几种方案:

1.在主线程中设置一自定义全局计数标志,在工作线程完成时,计数减一。主线程侦测该标志是否为0,一旦为0,表示所有工作线程已经完成。

2.使用Java标准的类CountDownLatch来完成这项工作,原理是一样的,计数。

CountDownLatch

CountDownLatch 初始化设置count,即等待(await)count个线程或一个线程count次计数,通过工作线程来countDown计数减一,直到计数为0,await阻塞结束。

设置的count不可更改,如需要动态设置计数的线程数,可以使用CyclicBarrier.

下面的例子,所有的工作线程中准备就绪以后,并不是直接运行,而是等待主线程的信号后再执行具体的操作。

    packagecom.example.multithread;importjava.util.concurrent.CountDownLatch;classDriver{privatestaticfinalintTOTAL_THREADS=10;privatefinalCountDownLatchmStartSignal=newCountDownLatch(1);privatefinalCountDownLatchmDoneSignal=newCountDownLatch(TOTAL_THREADS);voidmain(){for(inti=0;i<TOTAL_THREADS;i++){newThread(newWorker(mStartSignal,mDoneSignal,i)).start();}System.out.println("MainThreadNow:"+System.currentTimeMillis());doPrepareWork();//准备工作mStartSignal.countDown();//计数减一为0,工作线程真正启动具体操作doSomethingElse();//做点自己的事情try{mDoneSignal.await();//等待所有工作线程结束}catch(InterruptedExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}System.out.println("Allworkershavefinishednow.");System.out.println("MainThreadNow:"+System.currentTimeMillis());}voiddoPrepareWork(){System.out.println("Ready,GO!");}voiddoSomethingElse(){for(inti=0;i<100000;i++){;//delay}System.out.println("MainThreadDosomethingelse.");}}classWorkerimplementsRunnable{privatefinalCountDownLatchmStartSignal;privatefinalCountDownLatchmDoneSignal;privatefinalintmThreadIndex;Worker(finalCountDownLatchstartSignal,finalCountDownLatchdoneSignal,finalintthreadIndex){this.mDoneSignal=doneSignal;this.mStartSignal=startSignal;this.mThreadIndex=threadIndex;}@Overridepublicvoidrun(){//TODOAuto-generatedmethodstubtry{mStartSignal.await();//阻塞,等待mStartSignal计数为0运行后面的代码//所有的工作线程都在等待同一个启动的命令doWork();//具体操作System.out.println("Thread"+mThreadIndex+"DoneNow:"+System.currentTimeMillis());mDoneSignal.countDown();//完成以后计数减一}catch(InterruptedExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}}publicvoiddoWork(){for(inti=0;i<1000000;i++){;//耗时操作}System.out.println("Thread"+mThreadIndex+":dowork");}}publicclassCountDownLatchTest{publicstaticvoidmain(String[]args){//TODOAuto-generatedmethodstubnewDriver().main();}}

通过Executor启动线程:

    classCountDownLatchDriver2{privatestaticfinalintTOTAL_THREADS=10;

privatefinalCountDownLatchmDoneSignal=newCountDownLatch(TOTAL_THREADS);

voidmain(){System.out.println("MainThreadNow:"+System.currentTimeMillis());doPrepareWork();//准备工作Executorexecutor=Executors.newFixedThreadPool(TOTAL_THREADS);for(inti=0;i<TOTAL_THREADS;i++){//通过内建的线程池维护创建的线程executor.execute(newRunnableWorker(mDoneSignal,i));}doSomethingElse();//做点自己的事情try{mDoneSignal.await();//等待所有工作线程结束}catch(InterruptedExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}System.out.println("Allworkershavefinishednow.");System.out.println("MainThreadNow:"+System.currentTimeMillis());}voiddoPrepareWork(){System.out.println("Ready,GO!");}voiddoSomethingElse(){for(inti=0;i<100000;i++){;//delay}System.out.println("MainThreadDosomethingelse.");}}classRunnableWorkerimplementsRunnable{privatefinalCountDownLatchmDoneSignal;privatefinalintmThreadIndex;RunnableWorker(finalCountDownLatchdoneSignal,finalintthreadIndex){this.mDoneSignal=doneSignal;this.mThreadIndex=threadIndex;}@Overridepublicvoidrun(){//TODOAuto-generatedmethodstubdoWork();//具体操作System.out.println("Thread"+mThreadIndex+"DoneNow:"+System.currentTimeMillis());mDoneSignal.countDown();//完成以后计数减一//计数为0时,主线程接触阻塞,继续执行其他任务try{//可以继续做点其他的事情,与主线程无关了Thread.sleep(5000);System.out.println("Thread"+mThreadIndex+"Dosomethingelseafternotifingmainthread");}catch(InterruptedExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}}publicvoiddoWork(){for(inti=0;i<1000000;i++){;//耗时操作}System.out.println("Thread"+mThreadIndex+":dowork");}}

输出:

Main Thread Now:1359959480786Ready,GO!Thread 0:do workThread 0 Done Now:1359959480808Thread 1:do workThread 1 Done Now:1359959480811Thread 2:do workThread 2 Done Now:1359959480813Main Thread Do something else.Thread 3:do workThread 3 Done Now:1359959480825Thread 5:do workThread 5 Done Now:1359959480827Thread 7:do workThread 7 Done Now:1359959480829Thread 9:do workThread 9 Done Now:1359959480831Thread 4:do workThread 4 Done Now:1359959480833Thread 6:do workThread 6 Done Now:1359959480835Thread 8:do workThread 8 Done Now:1359959480837All workers have finished now.Main Thread Now:1359959480838Thread 0 Do something else after notifing main threadThread 1 Do something else after notifing main threadThread 2 Do something else after notifing main threadThread 3 Do something else after notifing main threadThread 9 Do something else after notifing main threadThread 7 Do something else after notifing main threadThread 5 Do something else after notifing main threadThread 4 Do something else after notifing main threadThread 6 Do something else after notifing main threadThread 8 Do something else after notifing main thread
CyclicBarrier
使用CyclickBarrier的例子:
    classWalkTarget{privatefinalintmCount=5;

privatefinalCyclicBarriermBarrier;ExecutorServicemExecutor;classBarrierActionimplementsRunnable{@Overridepublicvoidrun(){//TODOAuto-generatedmethodstubSystem.out.println("所有线程都已经完成任务,计数达到预设值");//mBarrier.reset();//恢复到初始化状态}}WalkTarget(){//初始化CyclicBarriermBarrier=newCyclicBarrier(mCount,newBarrierAction());mExecutor=Executors.newFixedThreadPool(mCount);for(inti=0;i<mCount;i++){//启动工作线程mExecutor.execute(newWalker(mBarrier,i));}}}//工作线程classWalkerimplementsRunnable{privatefinalCyclicBarriermBarrier;privatefinalintmThreadIndex;Walker(finalCyclicBarrierbarrier,finalintthreadIndex)

{mBarrier=barrier;mThreadIndex=threadIndex;}@Overridepublicvoidrun(){//TODOAuto-generatedmethodstubSystem.out.println("Thread"+mThreadIndex+"isrunning…");//执行任务try{TimeUnit.MILLISECONDS.sleep(5000);//dotask}catch(InterruptedExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}//完成任务以后,等待其他线程完成任务try{mBarrier.await();}catch(InterruptedExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}catch(BrokenBarrierExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}//其他线程任务都完成以后,阻塞解除,可以继续接下来的任务System.out.println("Thread"+mThreadIndex+"dosomethingelse");}}publicclassCountDownLatchTest{publicstaticvoidmain(String[]args){//TODOAuto-generatedmethodstub//newCountDownLatchDriver2().main();newWalkTarget();}}

输出(注意,只有所有的线程barrier.await之后才能继续执行其他的操作):

Thread 0 is running... Thread 2 is running... Thread 3 is running... Thread 1 is running... Thread 4 is running... 所有线程都已经完成任务,计数达到预设值 Thread 4 do something else Thread 0 do something else Thread 2 do something else Thread 3 do something else Thread 1 do something else

CountDownLatch和CyclicBarrier简单比较:

CountDownLatch

CyclicBarrier

软件包

java.util.concurrent

java.util.concurrent

适用情景

主线程等待多个工作线程结束

多个线程之间互相等待,直到所有线程达到一个障碍点(Barrier point)

主要方法

CountDownLatch(int count) (主线程调用)

初始化计数

CountDownLatch.await (主线程调用)

阻塞,直到等待计数为0解除阻塞

CountDownLatch.countDown

计数减一(工作线程调用)

CyclicBarrier(int parties,RunnablebarrierAction) //初始化参与者数量和障碍点执行Action,Action可选。由主线程初始化

CyclicBarrier.await() //由参与者调用

阻塞,直到所有线程达到屏障点

等待结束

各线程之间不再互相影响,可以继续做自己的事情。不再执行下一个目标工作。

在屏障点达到后,允许所有线程继续执行,达到下一个目标。可以重复使用CyclicBarrier

异常

如果其中一个线程由于中断,错误,或超时导致永久离开屏障点,其他线程也将抛出异常。

其他

如果BarrierAction不依赖于任何Party中的所有线程,那么在任何party中的一个线程被释放的时候,可以直接运行这个Action。

If(barrier.await()==2)

{

//do action

}

别人失去了信心,他却下决心实现自己的目标。

Java:多线程等待所有线程结束(CountDownLatch/CyclicBarrier) .

相关文章:

你感兴趣的文章:

标签云: