上篇JUC同步工具之Semaphore – 池塘里洗澡的鸭子 – 博客园 (cnblogs.com)示例中,资源释放一个线程就可以退出然后另一个线程可以使用了,那如果需要所有规定数量的资源同时释放了才可以退出,那如何实现同步呢?CountDownLatch。
从UML图中可以知道,CountDownLatch原理和Semaphore原理类似,同样是基于AQS,不过没有公平和非公平之分。
假设一个主线程要等待5个 Worker 线程执行完才能退出,看看使用CountDownLatch如何实现:
从上三图中的红框部分测试结果,通过CountDownLatch中的countDown和await方法共同作用实现了同步等待。具体如何实现呢?请看下面分析:
1、与Semaphore相似,CountDownLatch使用AQS的同步状态持有当期的计数:
2、await()实现分析:
CountDownLatch重写ryAcquireShared,从tryAcquireShared(…)方法的实现来看,只要state != 0,调用await()方法的线程便会被放入AQS的阻塞队列,进入阻塞状态,反之如果计数器已经到达零,会立即返回。
2、countDown()实现分析:
countDown()调用的AQS的模板方法releaseShared(),里面的tryReleaseShared(…)由CountDownLatch.Sync实现。从上面的代码可以看出,只有state=0,tryReleaseShared(…)才会返回true,然后执行doReleaseShared(…),一次性唤醒队列中所有阻塞的线程。
由于是基于AQS阻塞队列来实现的,所以可以让多个线程都阻塞在state=0条件上,通过countDown()一直减state,减到0后一次性唤醒所有线程。