简介:
CountDownLatch 是一个非常实用的多线程控制工具类,通常用来控制线程的等待,它可以让某个线程等待直到倒计时结束
CountDownLatch 提供了两个主要的方法,await()、countDown()。
await:使当前线程阻塞,等待计数器为 0
countDown:计数器减一,计数为零时,释放所有在等待的线程
实例:
public class CountDownLatchDemo implementsRunnable {static final CountDownLatch end = new CountDownLatch(10);static final CountDownLatchDemo demo = newCountDownLatchDemo();
@Overridepublic voidrun() {try{
Thread.sleep(new Random().nextInt(10) * 1000);
System.out.println("check complete...");
end.countDown();
}catch(InterruptedException e) {
e.printStackTrace();
}
}public static void main(String[] args) throwsInterruptedException {
ExecutorService exec= Executors.newFixedThreadPool(10);for (int i = 0;i < 10;i++) {
exec.submit(demo);
}
end.await();
System.out.println("Fire!");
exec.shutdown();
}
}
原理解析:
countDownLatch 的计数是通过一个共享变量(volatile)实现的,下面分析它的三个核心函数:构造函数,CountDownLatch(int count);阻塞线程,await();计数器减一,countDown()。
CountDownLatch(int count)
public CountDownLatch(intcount) {if (count < 0) throw new IllegalArgumentException("count < 0");this.sync = newSync(count);
}
其中 Sync 是 CountDownLatch 的内部类,并且 Sync 继承了 AbstractQueuedSynchronizer
private static final class Sync extendsAbstractQueuedSynchronizer {private static final long serialVersionUID = 4982264981922014374L;
Sync(intcount) {
setState(count);
}intgetCount() {returngetState();
}protected int tryAcquireShared(intacquires) {return (getState() == 0) ? 1 : -1;
}protected boolean tryReleaseShared(intreleases) {//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;
}
}
}
View Code
其中 setState 是设置 AbstractQueuedSynchronizer 中 state 变量,该变量声明了 volatile。
State 就是 countDownLatch 中的计数器。
await()
public void await() throwsInterruptedException {
sync.acquireSharedInterruptibly(1);
}public final boolean tryAcquireSharedNanos(int arg, longnanosTimeout)throwsInterruptedException {if(Thread.interrupted())throw newInterruptedException();return tryAcquireShared(arg) >= 0 ||doAcquireSharedNanos(arg, nanosTimeout);
}
acquireSharedInterruptibly() 的作用是获取共享锁,如果当前线程处于中断状态,则抛出 InterruptedException,否则,调用 tryAcquireShared(arg) 尝试获取共享锁,如果锁计数器 = 0,则表示锁为可获取状态,返回 1,否则,锁为不可获取状态,则返回 -1。
doAcquireSharedNanos() 会使当前线程一直等待,直到当前线程获取到共享锁(或线程被中断)才返回。
countDown()
public voidcountDown() {
sync.releaseShared(1);
}public final boolean releaseShared(intarg) {if(tryReleaseShared(arg)) {
doReleaseShared();return true;
}return false;
}
releaseShared() 目的是让当前线程释放它所持有的共享锁。
tryReleaseShared() 的作用是释放共享锁,将锁计数器的值减一。
总结
CountDownLatch 是通过共享锁实现的。CountDownLatch 构造函数传递 int 参数,该参数是计数器的初始状态,表示共享锁最多能被 count 个线程同时获取。
当某线程调用 CountDownLatch 的 await 方法时,该线程会等待共享锁可用时(计数器为 0 时),才能获取共享锁,进而继续执行。
每次执行 countDown 时,会将计数器减一。
参考资料