> 在我开门之前谁也别想动 CountDownLatch 是Java Concurrent 包里边的一个同步工具类。它可以使一个或多个线程等待一个事件发生。 CountDownLatch 有一个计数器,表示等待的事件数量。以及一个await方法,当计数器一直大于零的时候,会一直等待。 一般有两种用法,创建一组线程,让他们并发的执行 或者 等待,直到所有的线程完成任务。当然用来做一些有先后顺序的工作也很好用。 ### await方法 一直追踪这个方法,在`AbstractQueuedSynchronizer`有这段代码 ``` java 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里有个内部类`Sync`,实现了`AbstractQueuedSynchronizer`,在初始化CountDownLatch的时候,初始化Sync,同时生成一个 队列(链表),根据CountDownLatch(size)的size,来生成Node,在最后一个就剩head之前会一直循环(Await)。 也就是说,调用await的时候,尝试获取共享锁,然后失败,因为节点不是head,所以会加入到tail(CAS方式添加)。 ##### 1 ``` java CountDownLatch startLatch = new CountDownLatch(1); for (int i = 0; i < 10; i++) { new Thread(() -> { try { startLatch.await(); System.out.println(Instant.now()); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } System.out.println("start..."); startLatch.countDown(); ``` 所有线程因为count是1,被卡住,直到countdown。 ##### 2 ``` java CountDownLatch waitLatch = new CountDownLatch(10); for (int i = 0; i < 10; i++) { int finalI = i; new Thread(() -> { try { Thread.sleep(new Random().nextInt(2000)); System.out.println("i: " + finalI); } catch (InterruptedException e) { e.printStackTrace(); } finally { waitLatch.countDown(); } }).start(); } waitLatch.await(); System.out.println("end"); ``` 最后输出`end`被执行之前要先执行完之前的线程,因为count>0,如果count的初始值过小,就会提前输出最后的`end` ``` bash i: 8 i: 3 i: 6 i: 5 i: 0 end i: 4 i: 1 i: 9 i: 7 i: 2 ```