1. demo展示
代码逻辑展示了主线程中创建2个子线程分别去执行任务,主线程等2个子线程执行完毕后,再接着执行下面的代码;
常用场景:
- 分别计算,汇总结果。如,多个线程分别解析excel中的sheet,等待全部解析完毕后汇总结果;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class CountDownLatchDemo {
//定义一个倒计时闩锁
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
try {
TimeUnit.MICROSECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是线程1");
//释放一个
c.countDown();
}).start();
new Thread(() -> {
try {
TimeUnit.MICROSECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是线程2");
//释放一个
c.countDown();
}).start();
System.out.println("我是主线程,我要等那两个线程执行完毕...");
//等待倒计时为0
c.await();
System.out.println("我是主线程,那两个线程都执行完了");
}
}
输出:
我是主线程,我要等那两个线程执行完毕...
我是线程2
我是线程1
我是主线程,那两个线程都执行完了
2. 原理解析
- 先看构造函数new CountDownLatch(2)做了什么?
这是初始化了AQS子类,并将AQS的状态state设置为传入的2;public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
- 看c.countDown()做了什么?
它释放了一个共享锁状态,也就是state减1;public void countDown() { sync.releaseShared(1); }
- 再看c.await()做了什么?
await方法是CounDownLatch中定义的,它调用了其内部类Sync(也是AQS的子类)的获取共享锁的方法acquireSharedInterruptibly;
acquireSharedInterruptibly方法中调用了CountDownLatch内部类Sync中实现的获取共享锁的方法tryAcquireShared,返回值不小0就算获取到了锁,await方法就能返回了,如果返回值小于0将会进入阻塞等待;
CountDownLatch内部类Sync中tryAcquireShared的实现很简单,只要state=0就返回1,否则返回-1;上面说了返回一个不小于0的数字,c.await()就相当于获取到了锁,就可以返回了,主线程就可以继续执行了。
通过上面分析,每次c.countDown(),就会将state减1,state=0的时候主线程恢复执行;