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;}}