AQS---CountDownLatch
概述
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
CountDownLatch是一种线程同步工具 :允许其他线程阻塞等待,直到正在执行的线程完成;
A {@code CountDownLatch} is initialized with a given <em>count</em>.
CountDownLatch需要一个count进行初始化
The {@link #await await} methods block until the current count reaches zero due to invocations of the {@link #countDown} method, after which all waiting threads are released and any subsequent invocations of {@link #await await} return immediately.
调用await方法将会被阻塞 直到 调用countDown方法让count=0,
A {@code CountDownLatch} is a versatile synchronization tool and can be used for a number of purposes.
CountDownLatch是一个多功能同步工具,可以用于不同的目的;
A {@code CountDownLatch} initialized with a count of one serves as a simple on/off latch, or gate: all threads invoking {@link #await await} wait at the gate until it is opened by a thread invoking {@link #countDown}.
初始化count=1的CountDownLatch 可以当做一个简易开关:所有线程调用await将被阻塞等待 直到 正在执行的线程调用countDown;
A {@code CountDownLatch} initialized to N can be used to make one thread wait until N threads have completed some action, or some action has been completed N times.
初始化count=n的CountDownLatch 可以当做 一个线程阻塞等待 直到其他n个线程完成(或其他线程完成n次);
A useful property of a {@code CountDownLatch} is that it doesn't require that threads calling {@code countDown} wait for the count to reach zero before proceeding, it simply prevents any thread from proceeding past an {@link #await await} until all threads could pass.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | public class CountDownLatch { private static final class Sync extends AbstractQueuedSynchronizer { } private final Sync sync; public CountDownLatch( int count) { if (count < 0 ) throw new IllegalArgumentException( "count < 0" ); this .sync = new Sync(count); } /** * Causes the current thread to wait until the latch has counted down to zero, unless the thread is {@linkplain Thread#interrupt interrupted}. * 造成当前线程阻塞等待 直到 latch的count=0,除非线程被中断 * @throws InterruptedException */ public void await() throws InterruptedException { sync.acquireSharedInterruptibly( 1 ); } /** * Decrements the count of the latch, releasing all waiting threads if the count reaches zero. * 减少latch的count,如果count=0将释放所有等待的线程 * * If the current count is greater than zero then it is decremented. * 如果当前count>0 将会递减 * If the new count is zero then all waiting threads are re-enabled for thread scheduling purposes. * 如果count=0 ,所有等待线程将被重新调度 */ public void countDown() { sync.releaseShared( 1 ); } } |
使用场景
线程同步工具 :允许其他线程阻塞等待,直到正在执行的线程完成;
典型用法:
将一个程序分为n个互相独立的可解决任务,并创建值为n的CountDownLatch。
当每一个任务完成时,都会在这个锁存器上调用countDown,等待问题被解决的任务调用这个锁存器的await,将他们自己拦住,直至锁存器计数结束;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch( 3 ); Task task = new Task(countDownLatch); Thread t1 = new Thread(task); Thread t2 = new Thread(task); Thread t3 = new Thread(task); t1.start(); countDownLatch.await( 1 , TimeUnit.SECONDS); t2.start(); countDownLatch.await( 1 , TimeUnit.SECONDS); t3.start(); countDownLatch.await( 1 , TimeUnit.SECONDS); } static class Task implements Runnable{ private CountDownLatch countDownLatch; Task(CountDownLatch countDownLatch){ this .countDownLatch = countDownLatch; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " 正在执行任务" ); countDownLatch.countDown(); System.out.println(Thread.currentThread().getName() + " 任务结束,countDown" ); } public CountDownLatch getCountDownLatch() { return countDownLatch; } public void setCountDownLatch(CountDownLatch countDownLatch) { this .countDownLatch = countDownLatch; } } 结果: Thread- 0 正在执行任务 Thread- 0 任务结束,countDown Thread- 1 正在执行任务 Thread- 1 任务结束,countDown Thread- 2 正在执行任务 Thread- 2 任务结束,countDown |
实现思路
继承AQS,以共享模式访问共享资源,对指定的count进行cas操作;
链路
new CountDownLatch(3)
1 2 3 4 5 6 7 | /** * new CountDownLatch(3) 初始化AQS的state * * java.util.concurrent.CountDownLatch#CountDownLatch(int) * java.util.concurrent.CountDownLatch.Sync#Sync(int) * java.util.concurrent.locks.AbstractQueuedSynchronizer#setState(int) */ |
await()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | // java.util.concurrent.CountDownLatch.await() /** * Causes the current thread to wait until the latch has counted down to zero * await会将当前线程等待 直到 latch的count=0 * @throws InterruptedException */ public void await() throws InterruptedException { sync.acquireSharedInterruptibly( 1 ); } // java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly /** * Acquires in shared mode */ public final void acquireSharedInterruptibly( int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); // 如果以共享模式获取失败 -> 当前线程进入阻塞排队 if (tryAcquireShared(arg) < 0 ) doAcquireSharedInterruptibly(arg); } // java.util.concurrent.CountDownLatch.Sync.tryAcquireShared protected int tryAcquireShared( int acquires) { return (getState() == 0 ) ? 1 : - 1 ; } // java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly /** * Acquires in shared interruptible mode. * @param arg the acquire argument */ private void doAcquireSharedInterruptibly( int arg) throws InterruptedException { final AbstractQueuedSynchronizer.Node node = addWaiter(AbstractQueuedSynchronizer.Node.SHARED); boolean failed = true ; try { for (;;) { final AbstractQueuedSynchronizer.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); } } |
countDown()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | // java.util.concurrent.CountDownLatch.countDown /** * Decrements the count of the latch, releasing all waiting threads if the count reaches zero. * latch的count-1 */ public void countDown() { sync.releaseShared( 1 ); } // java.util.concurrent.locks.AbstractQueuedSynchronizer.releaseShared /** * Releases in shared mode. */ public final boolean releaseShared( int arg) { // 如果latch的count-1成功 -> 唤醒队列中正在等待的线程 if (tryReleaseShared(arg)) { doReleaseShared(); return true ; } return false ; } // java.util.concurrent.CountDownLatch.Sync.tryReleaseShared 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 ; } } // java.util.concurrent.locks.AbstractQueuedSynchronizer.doReleaseShared /** * Release action for shared mode -- signals successor and ensures propagation. * 以共享模式释放等待的线程 */ private void doReleaseShared() { /* * Ensure that a release propagates, even if there are other * in-progress acquires/releases. This proceeds in the usual * way of trying to unparkSuccessor of head if it needs * signal. But if it does not, status is set to PROPAGATE to * ensure that upon release, propagation continues. * Additionally, we must loop in case a new node is added * while we are doing this. Also, unlike other uses of * unparkSuccessor, we need to know if CAS to reset status * fails, if so rechecking. */ for (;;) { AbstractQueuedSynchronizer.Node h = head; if (h != null && h != tail) { int ws = h.waitStatus; if (ws == AbstractQueuedSynchronizer.Node.SIGNAL) { if (!compareAndSetWaitStatus(h, AbstractQueuedSynchronizer.Node.SIGNAL, 0 )) continue ; // loop to recheck cases unparkSuccessor(h); } else if (ws == 0 && !compareAndSetWaitStatus(h, 0 , AbstractQueuedSynchronizer.Node.PROPAGATE)) continue ; // loop on failed CAS } if (h == head) // loop if head changed break ; } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)