1. CountDownLatch 定义
CountDownLatch 可以理解为一个简单的计数器, 首先设定计数的值, 然后进行调用 await(PS: 调用 await 后, CountDownLatch会判断 AQS中State值是否为0, 不为0, 则线程节点进入 AQS的 Sync Queue 里面, 处于阻塞状态), 这时线程会阻塞, 直到AQS.state变成0, 则进行唤醒所有调用的 awiat 的线程
特点: 简单易用, 最常用于 Future 的实现
看下面的代码:
import java.util.concurrent.*;
/**
* Created by xjk on 2/12/17.
*/
public class KFuture<V> implements Future<V> {
private CountDownLatch latch; // 控制获取值等待
private volatile V result; // 执行结果
public KFuture() {
latch = new CountDownLatch(1);
}
/**
* cancel 执行计划
*/
public boolean cancel(boolean ignored) {
boolean cancelled = false;
if (latch.getCount() == 1) {
latch.countDown();
cancelled = true;
}
return cancelled;
}
/**
* 判断是否 cancel
*/
public boolean isCancelled() {
return latch.getCount() == 0 && result == null;
}
/**
* 判断任务是否执行
*/
@Override
public boolean isDone() {
return result != null;
}
/**
* 获取 result
*/
public V get() throws InterruptedException {
try {
latch.await();
return result;
} catch (InterruptedException e) {
throw new Error(e);
}
}
/**
* 定时获取 result
*/
@Override
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
try {
latch.await(timeout, unit);
return result;
} catch (InterruptedException e) {
throw new Error(e);
}
}
}
2. CountDownLatch 构造函数
CountDownLatch 的内部功能都是由 Sync 来实现的
/**
* 指定 latch 的数量
*/
public CountDownLatch(int count){
if(count < 0) throw new IllegalArgumentException(" count < 0 ");
this.sync = new Sync(count);
}
3. CountDownLatch 内部类 Sync
Sync 继承 AQS, 代理实现 await, coutDown
/**
* Synchronization control For CountDownLatch
* Use AQS state to represent count
*/
/**
* AQS 的继承类, 主要的 获取 释放操作
*/
private static final class Sync extends AbstractQueuedSynchronizer{
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count){
setState(count);
}
int getCount(){
return getState();
}
/**
* 判断是否正真的进行到了latch的位置, 也就是getState() == 0
*/
protected int tryAcquireShared(int acquires){
return (getState() == 0)? 1 : -1;
}
/**
* 进行释放
*/
protected boolean tryReleaseShared(int release){
// 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;
}
}
}
}
4. CountDownLatch 等待方法 awaitXX
/**
* 判断是否到 latch, 也就是 getState() == 0
*/
public void await() throws InterruptedException{
sync.acquireSharedInterruptibly(1);
}
/**
* 进行指定超时的 await
*/
public boolean await(long timeout, TimeUnit unit) throws InterruptedException{
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
5. CountDownLatch 获取资源方法 countDown
/**
* 释放获取 latch 的数量
*/
public void countDown(){
sync.releaseShared(1);
}
6. 总结
CountDownLatch主要用于控制资源的获取, 设定阀值, 一直 coutDown, 直到计数器为 0为止; CountDownLatch 主要用 AQS的共享方式; 在方法上最大的区别是调用 countDown()方法其实是获取 AQS内部的共享资源, 直到获取到 0 为止; 但要正真理解 CountDownLatch, 还需要看AQS的源码
参考:
Java 8 源码分析 AbstractQueuedSynchronizer
Java多线程之JUC包:CountDownLatch源码学习笔记