提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
作用
使线程A等待其他线程各自执行完毕后再执行,类似 Thread.join()。
举例:孙悟空收集七龙珠召唤神龙,如果孙悟空串行收集,会浪费太多时间。孙悟空 找了7个帮手,让他们去收集七龙珠。等到7个帮手全部收集完毕之后,孙悟空再召唤神龙。
使用
用法:线程A 调用CountDownLatch.await()开始阻塞等待,当所有执行线程都执行完毕并且都调用CountDownLatch.countDwon(),线程A被唤醒继续执行。
声明CountDownLatch需要指定当前线程等待线程的个数
final CountDownLatch countDownLatch = new CountDownLatch(2);
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("T1 开始执行");
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T1 执行完成");
}
},"Thread1").start();
new Thread(new Runnable(){
@Override
public void run() {
try {
System.out.println("T2 开始执行");
Thread.sleep(5000);
countDownLatch.countDown();
System.out.println("T2 执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Thread2").start();
new Thread(new Runnable(){
@Override
public void run() {
try {
System.out.println("T3 开始执行");
Thread.sleep(4000);
countDownLatch.countDown();
System.out.println("T3 执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Thread3").start();
执行结果如下:
T1 开始执行
T2 开始执行
T3 开始执行
T3 执行完毕
T2 执行完毕
T1 执行完成
设计思路
基于aqs
(0)共享模式,即等待线程可以有多个
(1)使用state表示当前正在执行的线程数量,每当一个线程执行完毕,就将state-1。一旦state=0,就会唤醒所有的等待线程。
(2)重写了AQS中tryAcquireShared()、tryReleaseShared(),根据CountDownLatch自身特性重新定义了竞争锁的策略
自身特性如下:
所有执行线程执行完毕 state=0
(3)所有等待线程之间以共享结点的方式进行阻塞,要唤醒就全部会被唤醒。
源码分析
CountDownLatch 初始化
对AQS中的state进行了初始化,表示被等待线程的数量
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
根据自身特性重写方法
state=0 说明所有执行线程执行完毕
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
cas对state进行-1操作,表示一个线程执行完毕
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
等待线程调用 await()
由于CountDownLatch自身实现了竞争锁逻辑,当前线程A发现state>0,说明执行线程还没有执行完毕,此时线程A阻塞。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
state<0 说明此时还有线程未执行完毕,所以当前线程应该进行等待
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
执行线程执行完毕后,调用countDown()
由于CountDownLatch自身实现了释放锁逻辑,当前线程A发现state=0,说明执行线程全部执行完毕,此时线程A唤醒所有阻塞线程。
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}