CountDownLatch把这个单词拆分成两部分,CountDown是倒计时的意思,Latch的意思是门闩,也就是锁的意思,所以CountDownLatch其实是一个倒计时锁,当倒计时不为0的时候,就会被锁阻塞,当倒计时为0时,锁会被释放,继续执行逻辑
先来一段demo代码
public class CountdownTest {
public static void main(String[] args){
CountDownLatch latch = new CountDownLatch(2);
System.out.println("main线程开始执行");
new Thread() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1 countDown");
latch.countDown();
}
}.start();
new Thread() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2 countDown");
latch.countDown();
}
}.start();
try {
System.out.println("被countDownLatch阻塞");
latch.await();
System.out.println("main线程继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出
main线程开始执行
被countDownLatch阻塞
线程1 countDown
线程2 countDown
main线程继续执行
从上面的demo中我们可以看到三个关键的地方,我们一个个来分析一下,首先是CountDownLatch的构造方法
CountDownLatch latch = new CountDownLatch(2);
这里传入的参数就是倒计时的次数,来看看源码
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
// Sync(int count) {
// setState(count);
// }
// 传入的参数,最后赋值给了state变量,这是AQS中的变量,AQS是并发包的基础
// state在AQS中就代表了重入加锁的次数,可以认为是加了count数量的锁
this.sync = new Sync(count);
}
接下来分析一下CountDownLatch的await方法
public void await() throws InterruptedException {
// 参数传入1
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 判断state是否等于0,如果等于则返回1,否则返回-1
if (tryAcquireShared(arg) < 0)
// 这里的代码涉及到了AQS中的Node链表的逻辑,所以不展开细讲
// 大意是如果state不等于0,说明现在倒计时未结束,通过LockSupport.park()操作将当前线程挂起
doAcquireSharedInterruptibly(arg);
}
CountDownLatch的await方法在计数器没有到0的时候,就会将线程挂起
最后是CountDownLatch的countDown方法
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
// 这一步通过CAS操作将state减1,如果state减为了0,才返回true
if (tryReleaseShared(arg)) {
// 涉及到了AQS中的Node链表逻辑,不展开细讲
// 这一步其实就是唤醒了被挂起的线程,让所有被CountDownLatch阻塞住的线程都继续往下执行
doReleaseShared();
return true;
}
return false;
}
讲完了CountDownLatch的构造方法,await方法和countDown方法,大家对CountDownLatch基本也就理解了
这里分析一下demo代码的运行流程,首先进入main方法,输出 main线程开始执行 ,之后开启了两个线程,都sleep了一秒,此时程序运行到await方法,发现此时计数器还不为0,所以输出 被countDownLatch阻塞 ,然后线程1和线程2都执行countDown方法,输出 线程1 countDown 和 线程2 countDown,此时计数器已经被减为0了,main线程继续执行,输出 main线程继续执行
CountDownLatch其实也很简单,构造方法就是设置倒计时的数,countDown就是进行倒计时,await方法就是如果倒计时还没结束的话,就挂起线程,等到倒计时结束后,将挂起的线程唤醒,继续执行之后的逻辑