ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

JUC-CountDownLatch

2026/8/27 12:09:01 拓冰建站 浏览量
JUC-CountDownLatch

1. 作用

允许一条或多条线程等待其他线程中一组操作完成后,再继续执行

收集龙珠,召唤神龙:委派7个人同时收集,主人一直等待,直到7个人完成后,主人再继续召唤神龙

2. 使用方式demo

public class CountDownLatchTest {public static void main(String[] args) throws InterruptedException {List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);CountDownLatch countDownLatch = new CountDownLatch(list.size());// 并行寻找龙珠for (Integer num : list) {new Thread(()->{search(countDownLatch,num);}).start();}// 主人一直等待,直到收集完成countDownLatch.await();System.out.println("召唤神龙");}/*** 收集龙珠* @param countDownLatch* @param num*/public static void search(CountDownLatch countDownLatch, int num) {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("找到了第:'" + num + "'颗龙珠");countDownLatch.countDown();}

3. 原理

  • 初始化latch
  • 将等 await() 的线程放入等待队列
  • 子任务完成后释放锁
    • 当state=0时,唤醒等待队列中的任务

3.1 初始化latch

CountDownLatch countDownLatch = new CountDownLatch(7);

同时会指定同步状态state被占用7次

3.2 将等 await() 的线程放入等待队列

主人进入等待队列,称为Node1

countDownLatch.await()  // main线程进入等待

ps: 如果其他人也需要等待(比克大魔王 也在悄悄的等待7人收集完成,也可调用该方法,称为Node2)

        new Thread(()->{try {countDownLatch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("比克大魔王收到收集完龙珠消息");}).start();
    public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);}public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();if (tryAcquireShared(arg) < 0)doAcquireSharedInterruptibly(arg);}protected int tryAcquireShared(int acquires) {return (getState() == 0) ? 1 : -1;}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 GCfailed = false;return;}}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}}

3.3 子任务完成后释放锁

countDownLatch.countDown();

    public void countDown() {sync.releaseShared(1);}public final boolean releaseShared(int arg) {// 是否释放锁成功if (tryReleaseShared(arg)) {// 唤醒等待队列中的任务doReleaseShared();return true;}return false;}// 尝试释放锁(-1后 state=0)protected boolean tryReleaseShared(int releases) {// Decrement count; signal when transition to zerofor (;;) {int c = getState();// c已经=0,表示等待队列是空的,不需要再唤醒(state总数=7,但是有10个任务调了 countDownLatch.countDown() 方法,第7次执行完就唤醒了等待队列中的任务,后面 2次不需要再唤醒等待队列中的任务)if (c == 0)return false;int nextc = c-1;// state=0 时返回true,表示后续需要唤醒等待队列中的任务if (compareAndSetState(c, nextc))return nextc == 0;}}// 释放锁 并且 唤醒等待的线程private void doReleaseShared() {for (;;) {Node h = head;if (h != null && h != tail) {int ws = h.waitStatus;if (ws == Node.SIGNAL) {if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))continue;            // loop to recheck cases// 唤醒等待队列中的任务unparkSuccessor(h);}else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue;                // loop on failed CAS}if (h == head)                   // loop if head changedbreak;}}