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

  

  

posted on   anpeiyong  阅读(15)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)

导航

< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5
点击右上角即可分享
微信分享提示