简介
CountDownLatch 是一个同步器,翻译过来就是倒计数,意思就是用倒数来计数,当为0的时候结束。
源码分析
public class CountDownLatch {
/**
* 同步器,继承于aqs用来计数
*/
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
//初始化设置状态,即设置初始化计数器
Sync(int count) {
setState(count);
}
//获取state 即获取当前的计数器
int getCount() {
return getState();
}
//重写父类方法,尝试判断当前值是否为0
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
//重写父类方 尝试判断是否-1是否为0
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
//cas 替换state值,如果当前不匹配则循环直至state为0或者匹配成功
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
private final Sync sync;
//初始化 其实就是去初始化sync
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
public void await() throws InterruptedException {
//如果计数器还大于0则阻塞当前线程 直到计数器=0为止
sync.acquireSharedInterruptibly(1);
}
//要么一直阻塞到时间过期,要么计数器=0
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
//计数器-1 如果-1后=0 则释放线程
public void countDown() {
sync.releaseShared(1);
}
//获取当前计数器
public long getCount() {
return sync.getCount();
}
public String toString() {
return super.toString() + "[Count = " + sync.getCount() + "]";
}
}
CountDownLatch源码之所以简单得易于AbstractQueuedSynchronizer 同步器,基本上所有的操作都是由AbstractQueuedSynchronizer 处理
简单例子
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(2);
new Thread(new Runnable() {
@Override
public void run() {
try {
countDownLatch.await();
System.out.println("释放线程1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
countDownLatch.await();
System.out.println("释放线程2");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("计数器-1");
countDownLatch.countDown();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("计数器-1");
countDownLatch.countDown();
}
}).start();
}
}
总结:
我们前面讲到CyclicBarrier同步器,两者功能类似,都是倒计数,当为0时,释放阻塞线程,但是CyclicBarrier针对的是主线程或者说一个线程,CountDownLatch针对的一组线程(上面例子中有两个线程);
CyclicBarrier可以接收Runnable参数,CountDownLatch不能;
CyclicBarrier通过执行await-1并且一直阻塞直到0大家一起接着执行,CountDownLatch通过countDown,不会阻塞;
这么说吧
CyclicBarrier :主线程和子线程最后会同时执行(如果await后面没有业务处理,和 CountDownLatch效果也类似)
CountDownLatch:一般子线程不管主线程,自己先执行掉