CountDownLatch
,谓之倒计数器。这个工具通常用来控制线程等待,一个或多个线程通过await()
方法,等待同组其他线程完成,整个过程是阻塞的。同组线程都完成后,才会继续往后执行。通俗地说,万事俱备再行动的意思。API中的描述如下:
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
我们以图示意:
看图说话
我们看下构造方法:
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
可以看到,依然是采用了继承了AQS
的Sync
,它依然是内部类。
锁的释放和等待分别为countdown()
和await()
方法,我们看下源码:
public void await() throws InterruptedException {
/**调用sync的共享锁,内部自旋通过getState()获取计数器的状态值,
*只有等 于零时才会cancel
*/
sync.acquireSharedInterruptibly(1);
}
public void countDown() {
sync.releaseShared(1);//将当前线程的状态归零
}
我们用等队友打球作为示例,演示下用法:
public class CountDownLatchTest {
static CountDownLatch countDownLatch ;
final static Random random = new Random();
static class Teammate implements Runnable {
String name;
public Teammate(String name) {
this.name = name;
}
@Override
public void run() {
int time = random.nextInt(10)+1;
try {
System.out.println(this.name+" 还有 "+time+" 分钟到达!");
Thread.sleep(time*1000);
System.out.println(this.name+" 到了");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
countDownLatch = new CountDownLatch(8);
for (int i = 1; i < 9; i++) {
new Thread(new Teammate("player" + i)).start();
}
countDownLatch.await();//只有8个队友都到了才会往下执行
System.out.println("人到齐了,4V4开始吧");
}
}