首页 > 代码库 > 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的实现原理