先看一段实例代码:
public static void main(String[] args) {
// 初始化 3个计数
CountDownLatch countDownLatch = new CountDownLatch(3);
new Thread(()->{
countDownLatch.countDown();// 第一次计数-1
System.out.println("123");
countDownLatch.countDown();// 第二次-1
System.out.println("124");
System.out.println(System.currentTimeMillis());
}).start();
new Thread(()->{
try {
Thread.sleep(3000);// 睡3s
countDownLatch.countDown();// 计数再-1
System.out.println("thread2 "+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
try {
countDownLatch.await();// 主线程等待计数为0
System.out.println("mThread " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
输出结果就是:
123
124
1547367298416
thread2 1547367301421
mThread 1547367301421
当线程2,睡3s后,计数-1 等于0,表示结束了,线程也结束了所以回到了主线程。
await() 方法 返回,打印时间。
这个类就像 join()方法,等待其他当线程结束,但CountDownLatch 提供了比join()方法更实在的一个功能就是await(long timeout, TimeUnit unit)
。带超时的功能。
可以看到 CountDownLatch内部有个Sync类他是实现自AbstractQueuedSynchronizer
(AQS)队列同步器,在上一篇已经有比较详细的介绍了,AQS的功能。
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
// 初始化 队列同步器
this.sync = new Sync(count);
}
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
// 设置state值,这里就像重入锁一样一共重入了几次或者是被共享了几次。
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
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;
}
}
}
CountDownLatch 的初始化 就是类似设值,这可直接猜测到 他的countdown 肯定是释放锁的过程,state-1
public void countDown() {
sync.releaseShared(1);
}
cyclic(循环)barrier (屏障),作用是:让一组线程到达这个屏障时被阻塞,最后一个线程到达的时候屏障被打开,所有被拦截的线程继续运行。
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
new Thread(()->{
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("123");
}).start();
new Thread(()->{
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("321");
}).start();
System.out.println("1111");
}
输出结果:
1111
321
123
上面的结果不够直观,如果只要去掉一个await(), 就会进入无限等待的状态。
当然也存在,超时的await() 方法。
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
// 首先需要获取锁
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
// 如果线程被中断,则直接打破屏障
breakBarrier();
throw new InterruptedException();
}
// 这里是关键,每次碰到个await,初始化的时候的count就会--,直到0
int index = --count;
if (index == 0) { // tripped
boolean ranAction = false;
try {
// 如果初始化有赋值过,命令,就是所有线程到的时候就会马上执行的runable
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
// 方法里面会打破 barrier
nextGeneration();
return 0;
} finally {
// 这里大概是怕command run 的时候会遇到异常,如果上面没有打破,最终还是会进行一次打破,如果然 Action是false的话
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
// 如果还不是最后一个线程,则会进入等待队列
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}