CountDownLatch是一个用来统计线程个数的工具,可以看作是个门闩(latch,门闩),必须等到线程齐了后才打开门闩。
CountDownLatch主要使用的方法是:
1.乘车去买菜,也可看作是工人上工和下工。这种场景需要的使用两个CountDownLatch。代码如下:
- private static final CountDownLatch people = new CountDownLatch(3);
- private static final CountDownLatch car = new CountDownLatch(1);
- static class Run3 implements Runnable {
- private String name;
- Run3(String name) {
- this.name = name;
- }
-
- @Override
- public void run() {
- try {
- System.out.println(name + "上车");
- car.await();
- System.out.println(name + "去采购东西");
- // doWork部分,不同线程耗时不一样
- int second = new Random().nextInt(20);
- Thread.sleep(second * 1000);
- System.out.println(name + "采购东西完毕,回到车上");
- people.countDown();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) throws InterruptedException {
- System.out.println("人员准备去采购");
- new Thread(new Run3("甲 ")).start();
- new Thread(new Run3("乙 ")).start();
- new Thread(new Run3("丙 ")).start();
- Thread.sleep(10 * 1000);
- // doWork
- car.countDown();
- System.out.println("车辆到达菜市场,人员下车");
- // 等待所有people完成采购
- people.await();
- System.out.println("车辆回家");
- }
-
- 输出日志:
- 人员准备去采购
- 甲 上车
- 乙 上车
- 丙 上车
- 车辆到达菜市场,人员下车
- 乙 去采购东西
- 甲 去采购东西
- 丙 去采购东西
- 甲 采购东西完毕,回到车上
- 丙 采购东西完毕,回到车上
- 乙 采购东西完毕,回到车上
- 车辆回家
2.另一个案例是单独的CountDownLatch完成的,可以看作是上述代码中的people。这个案例是把一个大任务分成了多个小任务让不同的人(线程)去处理,等所有人(线程)完成后,这个任务才算完成。可以类比的案例是,赛场跑道上多个运动员比赛,每个运动员都完成了比赛。那这个比赛项目就结束了。又或者是一个宝藏密室需要多个钥匙都插入钥匙孔才能打开大门。
CountDownLatch 内部也是有个Sync类继承了AbstractQueuedSynchronizer类,之前我们分析ReentrantLock、Semaphore时,发现这个父类他只提供模板方法。然而子类以不同的实现方式,来对应具体的业务案例。
CountDownLatch 的Sync类如下:
- private static final class Sync extends AbstractQueuedSynchronizer {
- private static final long serialVersionUID = 4982264981922014374L;
-
- Sync(int count) {
- setState(count);
- }
-
- int getCount() {
- return getState();
- }
-
- protected int tryAcquireShared(int acquires) {
- return (getState() == 0) ? 1 : -1;
- }
-
- protected boolean tryReleaseShared(int releases) {
- // Decrement count; signal when transition to zero
- for (;;) {
- int c = getState();
- if (c == 0)
- return false;
- int nextc = c-1;
- if (compareAndSetState(c, nextc))
- return nextc == 0;
- }
- }
- }
- // CountDownLatch的await方法
- public void await() throws InterruptedException {
- sync.acquireSharedInterruptibly(1);
- }
- // AQS类的acquireSharedInterruptibly方法,也就是CountDownLatch实际执行的方法
- public final void acquireSharedInterruptibly(int arg)
- throws InterruptedException {
- if (Thread.interrupted())
- throw new InterruptedException();
- if (tryAcquireShared(arg) < 0)
- doAcquireSharedInterruptibly(arg);
- }
- private void doAcquireSharedInterruptibly(int arg)
- throws InterruptedException {
- final Node node = addWaiter(Node.SHARED);
- boolean failed = true;
- try {
- for (;;) {
- final Node p = node.predecessor();
- if (p == head) {
- int r = tryAcquireShared(arg);
- if (r >= 0) {
- setHeadAndPropagate(node, r);
- p.next = null; // help GC
- failed = false;
- return;
- }
- }
- if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
- throw new InterruptedException();
- }
- } finally {
- if (failed)
- cancelAcquire(node);
- }
- }
- // CountDownLatch方法
- public void countDown() {
- sync.releaseShared(1);
- }
- // AQS的releaseShared
- public final boolean releaseShared(int arg) {
- if (tryReleaseShared(arg)) {
- doReleaseShared();
- return true;
- }
- return false;
- }
从这简单的代码里,我们可以了解到以下内容: