java多线程之CountDownLatch倒数闸门

  在多个线程进行协做时,一个常见的情景是一个线程须要等待另外的线程完成某些任务以后才能继续进行.在这种状况下,可使用CountDownLatch类,CountDownLatch类至关于多个线程等待开启的一个闸门.只有在其余线程完成任务以后,闸门才会打开,等待的线程才能运行.在建立CountDownLatch类的对象是须要指定等待完成的任务数目.一个CountDownLatch.类的对象被执行任务的线程和等待任务完成的线程说共享.当执行任务的线程完成其任务时,调用countDown方法来使待完成的任务数量减1.等待任务完成的线程经过调用await方法进入阻塞状态直到待完成的任务数量变为0.当全部任务都完成时,等待任务完成的线程会从await方法返回,能够继续执行后继的代码.CountDownLatch类的对象的使用是一次性的.一旦待完成的任务数量变为0,再调用await方法就再也不阻塞当前线程,而是当即返回.
倒数闸门的使用示例:
?
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import  java.util.concurrent.CountDownLatch;
 
/**
  * create at 11-9-17
  *
  * @author KETQI
  * @category CountDownLatch主要起倒计时计数器做用,它主要有两个方法await()和countDown()。
  * 一旦某个线程调用await()方法,那么该线程就会阻塞,等待CountDownLatch计数器倒计时归零,
  * 须要注意的是尽管线程调用await()方法后会阻塞,
  * 可是CountDownLatch容许别的线程调用countDown()方法,将计数器减一。
  * 也就是说调用计时器的线程阻塞后,能够利用别的线程控制调用线程什么时候重新开始运行。
  * <p/>
  * 该demo主要想要作的事就是:在主线程中建立N个子线程,让支线程等待主线程将开关计数器startSignal打开。
  * 而当主线程打开startSignal开关后,主线程要等待计数器doneSignal归零,
  * 而doneSignal计数器归零依赖于每一个支线程为主线程的计数器减一。
  * 因此当主线程打开开关后,支线程才能运行完毕,而只有支线程所有运行完毕,才能打开主线程的计数器。
  * 这样整个程序才能走完
  */
public  class  CountDownLatchDemo {
     public  static  final  int  N =  5 ;
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         // 用于向工做线程发送启动信号,由主线程调用
         CountDownLatch startSignal =  new  CountDownLatch( 1 );
         // 用于等待工做线程的结束信号,由子线程调用
         CountDownLatch doneSignal =  new  CountDownLatch(N);
         // 建立启动线程
         System.out.println( "开始建立并运行分支线程,且分支线程启动startSignal计数器,等待主线程将startSignal计数器打开" );
         for  ( int  i =  0 ; i < N; i++) {
             new  Thread( new  LatchWorker(startSignal, doneSignal),  "t"  + i).start();
         }
 
         // 主线程,递减开始计数器,让全部线程开始工做
         System.out.println( "主线程"  + Thread.currentThread().getName() +  "将startSignal计数器打开" );
         startSignal.countDown();
         // 主线程阻塞,等待全部线程完成
         System.out.println( "主线程"  + Thread.currentThread().getName() +  "开始倒计时5个数" );
         doneSignal.await();
         /**
          * 为何说运行到下一句,全部线程就所有运行完毕了呢。 由于主线程要倒计时5个数, 而产生的5个支线程在运行完毕前会将主线程的计数器减一,
          * 因此若是全部支线程运行完毕了 ,主线程才能继续运行主线程的最后一个打印程序
          */
         System.out.println( "全部线程运行完毕" );
     }
}
 
class  LatchWorker  implements  Runnable {
     // 用于等待启动信号
     private  final  CountDownLatch startSignal;
     // 用于发送结束信号
     private  final  CountDownLatch doneSignal;
 
     LatchWorker(CountDownLatch startSignal, CountDownLatch doneSignal) {
         this .startSignal = startSignal;
         this .doneSignal = doneSignal;
     }
 
     public  void  run() {
         try  {
             // 一旦调用await()方法,该线程就会开始阻塞。知道计数器startSignal为0
             System.out.println(Thread.currentThread().getName() +  " 开始调用await()方法,等待计数器startSignal被主线程打开" );
             startSignal.await();
             doWork();
             System.out.println(Thread.currentThread().getName() +  " 将主线程的计数器减一" );
             doneSignal.countDown(); // 发送完成信号
         catch  (InterruptedException ex) {
             ex.printStackTrace();
         }
     }
 
     void  doWork() {
         System.out.println(Thread.currentThread().getName() +  " 的计数器被打开,分支线程开始运行" );
         try  {
             Thread.sleep(( long ) Math.random() *  10000 );
         catch  (InterruptedException e) {
             e.printStackTrace();
         }
     }
}
相关文章
相关标签/搜索