简介
CountDownLatch可以阻塞某个线程,直到其内部计数器值为0为止或者当其他线程调用了阻塞线程的interrupted方法为止,而内部的计数器需要通过其他线程来减少
示例
public class Main implements Runnable {
private static CountDownLatch mCountDownLatch =new CountDownLatch(10);
public Main(){
}
public static void main(String[] args) {
try {
List<Thread> workers = Stream
.generate(() -> new Thread(new Main()))
.limit(10)
.collect(toList());
workers.forEach(Thread::start);
System.out.println("等待子线程完成工作");
mCountDownLatch.await();
System.out.println("开始下一步"+mCountDownLatch.getCount());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
Thread.sleep(300);
mCountDownLatch.countDown();
System.out.println(Thread.currentThread().getName() +"完成工作");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
构造CountDownLatch时需要传入一个计数值,通过其他线程调用countDown来减少。主线程中通过await方法来阻塞,直到内部计数器为0时或者被中断。
但是,如果在其他线程countDown前发生错误怎么办。可以使用try catch finally语句把他包裹,或者也可以使用await的另一个重载方法,在给定的时间内如果计数器还没为0,那么放弃等待。
mCountDownLatch.await(5,TimeUnit.SECONDS);
public class Main implements Runnable {
private static CountDownLatch mCountDownLatch =new CountDownLatch(10);
public Main(){
}
public static void main(String[] args) {
try {
List<Thread> workers = Stream
.generate(() -> new Thread(new Main()))
.limit(10)
.collect(toList());
workers.forEach(Thread::start);
System.out.println("等待子线程完成工作");
mCountDownLatch.await(5,TimeUnit.SECONDS);
System.out.println("开始下一步"+mCountDownLatch.getCount());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
Thread.sleep(2000);
mCountDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
getCount可以获取当前计数器的值
原理
CountDownLatch是通过AQS实现的,CountDownLatch的计数器实际会赋值给AQS的状态变量state
await方法也是调用了AQS的acquireSharedInterruptibly,这个方法用来获取共享资源时可被中断的方法.,
当发现线程被标明中断后,抛出异常,否则下一步,而tryAcquireShared只是判断了count是不是为0,不为0返回-1,进入doAcquireSharedInterruptibly阻塞当前线程
countDown将调用tryReleaseShared()减1.
tryReleaseShared()方法中通过CAS直到成功完成计数器减1并更新到state为止
通过CAS失败后循环重试,否则判断当前计时器是不是为0,为0就表示最后一个线程调用了countDown,那么还需要通过doReleaseShared唤醒被await方法阻塞的线程,