CountDownLatch是Java中的一个同步工具类,用于控制多线程并发执行中的同步问题。在多线程并发执行任务时,有时需要让某些线程等待某些条件达成后再开始执行,这时就可以使用CountDownLatch来实现。
整体架构
构造函数
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源码解读(一) |