java异步转同步CountDownLatch

java异步转同步CountDownLatch

在我们使用java异步编程的过程中,如果碰上需要异步转同步的场景,就可以使用Java 1.5后给我们提供的类:CountDownLatch

一、作用

1.主线程等待子线程执行完毕后再开始执行

2.程序启动过程中等待所有线程初始化操作完成后再执行后面的操作

二、怎么使用
//CountDownLatch使用很简单,只有一个Int有参构造,所以创建的时候必须指定一个int数字,下面称之为N
CountDownLatch count = new CountDownLatch(2);

注意:N的值必须 >=0,小于0会出现异常:java.lang.IllegalArgumentException: count < 0

其次,如果N==0,程序不会报错,但这个CountDownLatch对象没有意义,即无法进行异步转同步,因为计数器本身就是0,不需要递减为0

三、核心方法
//调用该方法后,当前线程等待,需要其他线程调用countDown()方法后,才能继续执行
count.await();
//和上面的await()方法对应,同时跟计数器N大小对应,当主线程调用await()方法后,子线程需要调用N次countDown()后,主线程才会开始执行,这个N就是new CountDownLatch(N)这里的N。
count.countDown();
//重载方法,功能跟await()类似,但是可以指定一个时间,达到这个时间后,无论子线程有没有执行countDown方法,主线程都会结束等待,开始执行。如果子进程提前执行了countDown方法,则主线程会提前开始运行,而不需要等时间结束
count.await(2000, TimeUnit.MILLISECONDS);
参数1:时间跨度
参数2:时间单位,这里是毫秒,即2s后,无论子线程有没有执行countDown(),主线程都会开始执行
四、案例一:主线程等待两个子线程执行结束
   public class demo1 {
    public static void main(String[] args) throws InterruptedException {

        //创建一个CountDownLatch对象,计数器N为2,需要执行两次countDown()
        CountDownLatch count = new CountDownLatch(2);
        //创建线程1,休眠3s后执行count.countDown()方法,唤醒主线程继续执行
        new Thread(() -> {
            try {
                //休眠3秒
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
            System.out.println("子线程1初始化结束,countDown减一");
            count.countDown();//计数器减一,减到0时,主线程开始执行
        }).start();
        //创建线程2,休眠3s后执行count.countDown()方法,唤醒主线程继续执行
        new Thread(() -> {
            try {
                //休眠3秒
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
            System.out.println("子线程2初始化结束,countDown减一");
            count.countDown();//计数器减一,减到0时,主线程开始执行
        }).start();

        System.out.println("主线程开始等待");
        count.await();//调用该方法后,主线程开始等待,等待子线程执行countDown()

        //子线程调用countDown()方法后主线程开始执行
        System.out.println("主线程开始执行,程序初始化成功");

    }
    
}

在这里插入图片描述
在这里插入图片描述

运行结果:主线程开始等待,等待两个子线程结束后再开始执行

可以看出来,运行结果有两种,一种是线程1先结束,一种是线程2先结束,但无论哪种情况,都需要两个子线程都结束后才会执行主线程,由此可以看出countDownLatch只能保证主线程等待,不能保证子线程的执行顺序,只要最后子线程都执行结束并调用countDown()方法,主线程就能继续执行。

案例二、一个子线程执行两次countDown方法
public class demo1 {
    public static void main(String[] args) throws InterruptedException {

        //创建一个CountDownLatch对象,计数器N为2,需要执行两次countDown()
        CountDownLatch count = new CountDownLatch(2);
        //创建线程1,休眠3s后执行count.countDown()方法,唤醒主线程继续执行
        new Thread(() -> {
            try {
                //休眠3秒
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
            System.out.println("子线程1初始化结束,countDown减2");
            count.countDown();//计数器减一,减到0时,主线程开始执行
            count.countDown();//计数器减一,减到0时,主线程开始执行
        }).start();


        System.out.println("主线程开始等待");
        count.await();//调用该方法后,主线程开始等待,等待子线程执行countDown()

        //子线程调用countDown()方法后主线程开始执行
        System.out.println("主线程开始执行,程序初始化成功");

    }
}

在这里插入图片描述

结果:尽管计数器N=2,而只有一条子线程,但是依然可以唤醒主线程,由此可知,N≠线程数量,N=countDown()方法执行次数。无论有几条线程,只要最终执行的countDown()方法次数=N,主线程都能被唤醒。

案例三、主线程定时唤醒
public class demo1 {
    public static void main(String[] args) throws InterruptedException {

        //创建一个CountDownLatch对象,计数器N为2,需要执行两次countDown()
        CountDownLatch count = new CountDownLatch(2);
        //创建线程1,休眠3s后执行count.countDown()方法,唤醒主线程继续执行
        new Thread(() -> {
            try {
                //休眠3秒
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
            System.out.println("子线程1初始化结束,countDown减2");
            count.countDown();//计数器减一,减到0时,主线程开始执行
            count.countDown();//计数器减一,减到0时,主线程开始执行
        }).start();

        System.out.println("主线程开始等待");
        //2s后无论子线程有没有执行countDown(),主线程都会开始执行
        count.await(2000,TimeUnit.MILLISECONDS);

        //子线程调用countDown()方法后主线程开始执行
        System.out.println("主线程开始执行,程序初始化成功");

    }
}

在这里插入图片描述

结果:由于子线程会休眠3s,而主线程只等待2s,所以在子线程执行结束之前,主线程就被唤醒了,然后子线程才执行结束。

结论

CountDownLatch count = new CountDownLatch(N);

1.调用count.await()方法后,无论哪个线程,几个线程,只要执行N次count.countDown()方法,都能唤醒等待线程。

2. count.await(2000,TimeUnit.MILLISECONDS);
2s后无论其他线程有没有执行countDown(),等待线程都会开始执行,2s内执行完countDown(),则会提前唤醒等待线程。

															【end】

如果觉得文章对你有帮助的话,可以微信关注我的公众号:码农小诚
关注我的公众号更多技术文章分享实时更新,与你共同成长,回复【555】还有55本java技术书籍,免费送。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小诚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值