public class CountDownLatchTest01 {
public static void main(String[] args) throws InterruptedException {
//发令枪准备
CountDownLatch startSignal=new CountDownLatch(1);
//5个线程要一起到终点
CountDownLatch endSignal=new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(new WorkerTest(startSignal,endSignal),"我是:"+i).start();
}
TimeUnit.SECONDS.sleep(3);
startSignal.countDown();
System.out.println("裁判:所有线程准备完毕,预备,跑!");
endSignal.await();
System.out.println("裁判:友谊第一,比赛第二,大家都到终点了,一起坐车回家!");
}
}
class WorkerTest implements Runnable{
private CountDownLatch startSignal;
private CountDownLatch endSignal;
public WorkerTest(CountDownLatch startSignal, CountDownLatch endSignal) {
this.startSignal = startSignal;
this.endSignal = endSignal;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"线程,开始等待起跑口令。。。。");
startSignal.await();
System.out.println(Thread.currentThread().getName()+"线程,加速gogogo");
System.out.println(Thread.currentThread().getName()+"线程,到终点了,其他人呢");
endSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
CountDownLatch 被人称作减法计数器,但是实际应用的时候,按照JDK文档的解释,可以有两种场景适用。
第一个是作为发令枪,场景是所有的线程在启动的时候,调用CountDownLatch 的await方法进行阻塞,然后通过调用countDown()方法,让阻塞的线程继续执行,一般这样我们可以new CountDownLatch(1)计数为1
第二个是作为一个上车关门条件,好比一辆巴士,要等所有乘客上车才可以关门开车。主要判断所有的线程执行完毕后,进行一些业务操作。此种场景下,一般是N个线程,则new CountDownLatch(N),然后在循环创建线程结束后,在主方法中调用await方法进行阻塞,最后在线程内部方法执行完毕后,进行countDown操作。这样当所有线程执行完毕后,主线程才会继续执行。
上述代码模拟5个线程进行跑步比赛,比赛完成后要一起坐车回家。运行结果如下:
我是:1线程,开始等待起跑口令。。。。
我是:4线程,开始等待起跑口令。。。。
我是:0线程,开始等待起跑口令。。。。
我是:3线程,开始等待起跑口令。。。。
我是:2线程,开始等待起跑口令。。。。
裁判:所有线程准备完毕,预备,跑!
我是:0线程,加速gogogo
我是:0线程,到终点了,其他人呢
我是:2线程,加速gogogo
我是:2线程,到终点了,其他人呢
我是:4线程,加速gogogo
我是:4线程,到终点了,其他人呢
我是:3线程,加速gogogo
我是:3线程,到终点了,其他人呢
我是:1线程,加速gogogo
我是:1线程,到终点了,其他人呢
裁判:友谊第一,比赛第二,大家都到终点了,一起坐车回家!
这其中要注意,第一次打印裁判所有线程准备完毕,预备,跑!如果没有TimeUnit.SECONDS.sleep(3);打印出来的结果,会和线程的开始等待等,不会按照顺序执行的。
为了演示效果才添加了延迟,实际生产过程中,不能按照此方法来进行主线程与其他线程的同步。
思考:应用场景还有哪些?现在能想到一个,是可以作为多线程并发的测试,比如循环创建1000个线程,最开始await,调用CountDown方法,来模拟线程并发的场景。
大家留言交流下,看看还有没有其他适用场景?