并发-AQS之CountDownLatch源码解读

121 阅读2分钟

CountDownLatch是Java中的一个同步工具类,用于控制多线程并发执行中的同步问题。在多线程并发执行任务时,有时需要让某些线程等待某些条件达成后再开始执行,这时就可以使用CountDownLatch来实现。

整体架构

image.png

构造函数

count计数器初始值,一般表示需要等待的线程数

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

countDown

将计数器减一

public void countDown() {
    //释放一个计数器
    sync.releaseShared(1);
}
//AQS方法
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

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

await

等待state=0唤醒线程继续执行,可中断

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) {
    //直到state=0,才获取资源可唤醒线程
    return (getState() == 0) ? 1 : -1;
}

await(long timeout, TimeUnit unit)

限定时间内等待

public boolean await(long timeout, TimeUnit unit)
    throws InterruptedException {
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    return tryAcquireShared(arg) >= 0 ||
        doAcquireSharedNanos(arg, nanosTimeout);
}
private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
        throws InterruptedException {
    if (nanosTimeout <= 0L)
        return false;
    final long deadline = System.nanoTime() + nanosTimeout;
    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 true;
                }
            }
            nanosTimeout = deadline - System.nanoTime();
            if (nanosTimeout <= 0L)
                return false;
            if (shouldParkAfterFailedAcquire(p, node) &&
                nanosTimeout > spinForTimeoutThreshold)
                LockSupport.parkNanos(this, nanosTimeout);
            if (Thread.interrupted())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

getCount

获取当前剩余资源数

public long getCount() {
    return sync.getCount();
}
int getCount() {
    return getState();
}

JDK中实现AQS简介

同步工具与AQS关联详细介绍
AQS原理讲解AQS原理介绍并发-AQS原理讲解
ReentrantLock使用AQS保存锁重复持有的次数。当一个线程获取锁时,ReentrantLock记录当前获得锁的线程标识,用于检测是否重复获取,以及错误线程试图解锁操作时异常情况的处理。AQS之Reentrantlonk源码解读
Semaphore使用AQS同步状态来保存信号量的当前计数。tryRelease会增加计数,acquireShared会减少计数。Semaphore 源码分析以及AQS共享加解锁
CountDownLatch在多线程并发执行任务时,有时需要让某些线程等待某些条件达成后再开始执行,这时就可以使用CountDownLatch来实现CountDownLatch 源码分析
ThreadPoolExecutor创建线程池中的工作线程worker继承AQS,实现独占资源参考 并发-AQS之ThreadPoolExecutor源码解读(一)
CyclicBarrier多个线程等待彼此达到一个共同的屏障点,然后同时继续执行。并发-AQS之CyclicBarrier源码解读
ReentrantReadWriteLock可重入读写锁,它允许多个线程同时读取一个共享资源,但只允许一个线程写入该共享资源。参考 并发-AQS之ReentrantReadWriteLock源码解读(一)