天天看点

JUC练习代码-CountDownLatch用法

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方法,来模拟线程并发的场景。

大家留言交流下,看看还有没有其他适用场景?