Java并发新构件之CounDownLatch

本文介绍 CountDownLatch 的使用方法,通过示例代码展示了如何利用 CountDownLatch 同步多个任务,确保一组任务在另一组任务完成后执行。

    CountDownLatch主要用于同步一个或多个任务,强制它们等待由其他任务执行的一组操作完成。

    你可以向CountDownLatch对象设置一个初始计数值,任何在这个对象上调用wait()的方法都将阻塞,直到这个计数值达到0.其他任务在结束其工作时,可以在该对象上调用countDown()来减小这个计数值,你可以通过调用getCount()方法来获取当前的计数值。CountDownLatch被设计为只触发一次,计数值不能被重置。如果你需要能够重置计数值的版本,则可以使用CyclicBarrier。

    调用countDown()的任务在产生这个调用时并没有阻塞,只有对await()的调用会被阻塞,直到计数值到达0。

    CountDownLatch的典型用法是将一个程序分为n个互相独立的可解决人物,并创建值为0的CountDownLatch。当每个任务完成是,都会在这个锁存器上调用countDown()。等待问题被解决的任务在这个锁存器上调用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
import  java.util.Random;
import  java.util.concurrent.CountDownLatch;
import  java.util.concurrent.DelayQueue;
import  java.util.concurrent.ExecutorService;
import  java.util.concurrent.Executors;
import  java.util.concurrent.TimeUnit;
 
class  TaskPortion  implements  Runnable {
     private  static  int  counter =  0 ;
     private  final  int  id = counter++;
     private  static  Random random =  new  Random();
     private  final  CountDownLatch latch;
     public  TaskPortion(CountDownLatch latch) {
         this .latch = latch;
     }
     @Override
     public  void  run() {
         try  {
             doWork();
             latch.countDown(); //普通任务执行完后,调用countDown()方法,减少count的值
             System.out.println( this  " completed. count="  + latch.getCount());
         catch  (InterruptedException e) {
             
         }
     }
     
     public  void  doWork()  throws  InterruptedException {
         TimeUnit.MILLISECONDS.sleep(random.nextInt( 2000 ));
     }
     
     @Override
     public  String toString() {
         return  String.format( "%1$-2d " , id);
     }
}
 
class  WaitingTask  implements  Runnable {
     private  static  int  counter =  0 ;
     private  final  int  id = counter++;
     private  final  CountDownLatch latch;
     public  WaitingTask(CountDownLatch latch) {
         this .latch = latch;
     }
     @Override
     public  void  run() {
         try  {
             //这些后续任务需要等到之前的任务都执行完成后才能执行,即count=0时
             latch.await();
             System.out.println( "Latch barrier passed for "  this );
         catch  (InterruptedException e) {
             System.out.println( this  " interrupted." );
         }
     }
     
     @Override
     public  String toString() {
         return  String.format( "WaitingTask %1$-2d " , id);
     }
}
 
public  class  CountDownLatchDemo {
     static  final  int  SIZE =  10 ;
     public  static  void  main(String[] args) {
         CountDownLatch latch =  new  CountDownLatch(SIZE);
         ExecutorService exec = Executors.newCachedThreadPool();
         //10个WaitingTask
         for  ( int  i =  0 ; i <  5 ; i++) {
             exec.execute( new  WaitingTask(latch));
         }
         //100个任务,这100个任务要先执行才会执行WaitingTask
         for  ( int  i =  0 ; i < SIZE; i++) {
             exec.execute( new  TaskPortion(latch));
         }
         System.out.println( "Launched all tasks." );
         exec.shutdown(); //当所有的任务都结束时,关闭exec
     }
}

执行结果(可能的结果):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Launched all tasks.
4    completed. count= 9
6    completed. count= 8
3    completed. count= 7
0    completed. count= 6
2    completed. count= 5
1    completed. count= 4
5    completed. count= 3
7    completed. count= 2
9    completed. count= 1
8    completed. count= 0
Latch barrier passed  for  WaitingTask  0  
Latch barrier passed  for  WaitingTask  2  
Latch barrier passed  for  WaitingTask  1  
Latch barrier passed  for  WaitingTask  3  
Latch barrier passed  for  WaitingTask  4

    从结果中可以看到,所有的WaitingTask都是在所有的TaskPortion执行完成之后执行的。

    TaskPortion将随机的休眠一段时间,以模拟这部分工作的完成。而WaitingTask表示系统中必须等待的部分,它要等到问题的初始部分完成后才能执行。注意:所有任务都使用了在main()中定义的同一个CountDownLatch对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值