首页 > 代码库 > CountDownLatch的实现原理
CountDownLatch的实现原理
CountDownLatch是java并发包中辅助并发的工具类,目的是让并发运行的代码在某一个执行点阻塞,直到所有条件都满足,这里的条件就是调用countDown()方法,有点类似计数器的功能。
用法如
public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(2); //如果没有countDown()操作,直接调用await方法则永远不会打印最后一行 countDownLatch.countDown(); countDownLatch.countDown(); countDownLatch.await(); System.out.println("运行结束"); }
构造函数中传入的数字2,表示需要2次countDown()方法调用,否则代码会一直阻塞在await()方法调用处
比较常见的用法如,主线程声明一个CountDownLatch,然后多线程countDown,主线程在等待
1 public static void testMultiThread() throws InterruptedException { 2 int threadNum = 2; 3 final CountDownLatch countDownLatch = new CountDownLatch(threadNum); 4 ExecutorService executorService = Executors.newFixedThreadPool(threadNum); 5 for(int i=0;i<threadNum;i++){ 6 executorService.execute(new Runnable() { 7 public void run() { 8 System.out.println("我的任务,打印出一句话"); 9 countDownLatch.countDown();10 }11 });12 }13 countDownLatch.await();14 System.out.println("全部任务都结束了,欧耶");15 executorService.shutdown();16 }
运行结果
我的任务,打印出一句话我的任务,打印出一句话全部任务都结束了,欧耶Process finished with exit code 0
如果把第三行代码修改成
3 final CountDownLatch countDownLatch = new CountDownLatch(threadNum+1);
那么程序将永远无法打印出
全部任务都结束了,欧耶
以上是这个类的表象行为,那么它是如何在多线程做到这样的功能呢
先来看看它的类结构
CountDownLacth中,有6个public的方法,一个内部私有类Sync,及一个Sync实例的变量sync
Sync是这个类的关键,它保证了countDown(),await()方法在多线程场景下可以保证countDownLatch的可见性(正常的同步)
我们先来自己实现一个CountDownLacth类,使用synchronized关键字实现
MyCountDownLatch模拟了countDown和await方法,通过synchronized和私有变量state来达到这个目的。synchronized的劣势在于锁机制完全互斥,并发量高时性能下降比较明显,无法维持常态化的性能(JDK 5)。因此CountDownLatch以及并发包中的类都采用了取巧的方式,通过线程自旋来追求线程响应时间,而不是让线程只能一直等待锁被释放再竞争。1.6之后,synchronized的性能和ReentrantLock的性能其实已经相当,偏向锁也改进了一个线程重复获取锁时不需要cpu切换上下文。
CountDownLatch的实现原理