Java并发工具类之CountDownLatch

本文详细介绍了Java中的并发工具类CountDownLatch和CyclicBarrier,通过实例展示了它们在多线程场景下的应用。CountDownLatch用于让一个线程等待其他线程完成操作,其计数不可重置;CyclicBarrier则允许一组线程相互等待,计数可重置。此外,还对比了CountDownLatch与join方法在同步控制上的区别,并提供了使用线程池时的同步解决方案。
摘要由CSDN通过智能技术生成

CountDownLatch简介

在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

用给定的计数初始化CountDownLatch,由于调用了countDown()方法,所以在当前计数到达零之前,await()方法会一直受阻塞,之后,会释放所有等待的 线程 ,await的所有后续调用都将立即返回。

和CyclicBarrier的区别?

  1. CountDownLatch 的作用是允许1或者N个线程等待其他线程 完成执行;而CyclicBarrier则是允许N个线程相互等待。

  2. CountDownLatch的计数器无法重置;CyclicBarrier的计数器可以被重置后使用,因此它被 称为是循环的barrier。

内部用共享锁来实现。

API

CountDownLatch.countDown()
CountDownLatch.await();

代码示例

比如陪媳妇去看病。
医院里边排队的人很多,如果一个人的话,要先看大夫,看完大夫再去排队交钱取药。
现在我们是双核,可以同时做这两个事(多线程)。
假设看大夫花3秒钟,排队交费取药花5秒钟。我们同时搞的话,5秒钟我们就能完成,然后一起回家(回到主线程)。

/**
 * 看大夫任务
 */
public class SeeDoctorTask implements Runnable {
    private CountDownLatch countDownLatch;

    public SeeDoctorTask(CountDownLatch countDownLatch){
        this.countDownLatch = countDownLatch;
    }

    public void run() {
        try {
            System.out.println("开始看医生");
            Thread.sleep(3000);
            System.out.println("看医生结束,准备离开病房");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            if (countDownLatch != null)
                countDownLatch.countDown();
        }
    }

}

/**
 * 排队的任务
 */
public class QueueTask implements Runnable {

    private CountDownLatch countDownLatch;

    public QueueTask(CountDownLatch countDownLatch){
        this.countDownLatch = countDownLatch;
    }
    public void run() {
        try {
            System.out.println("开始在医院药房排队买药....");
            Thread.sleep(5000);
            System.out.println("排队成功,可以开始缴费买药");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            if (countDownLatch != null)
                countDownLatch.countDown();
        }
    }
}

/**
 * 配媳妇去看病,轮到媳妇看大夫时
 * 我就开始去排队准备交钱了。
 */
public class CountDownLaunchRunner {

    public static void main(String[] args) throws InterruptedException {
        long now = System.currentTimeMillis();
        CountDownLatch countDownLatch = new CountDownLatch(2);

        new Thread(new SeeDoctorTask(countDownLatch)).start();
        new Thread(new QueueTask(countDownLatch)).start();
        //等待线程池中的2个任务执行完毕,否则一直
        countDownLatch.await();
        System.out.println("over,回家 cost:"+(System.currentTimeMillis()-now));
    }
}

用途

  1. 确保某个计算在其需要的所有资源都被初始化之后才执行
  2. 确保某个服务在其依赖的所有其他服务都已经启动之后才启动
  3. 等待直到每个操作的所有参与者都就绪再执行(比如打麻将时需要等待四个玩家就绪)

案例介绍

主线程中启动多个线程去执行任务,并且主线程需要等待所有子线程执行完毕后去汇总:

  1. 使用 join 来实现
public class JoinCountDownLatchTest {
    public static void main( String[] args ) throws InterruptedException {
        Thread t1 = new Thread(()->{

        });

        Thread t2 = new Thread(()->{

        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("all parse finish..");

    }
}

  1. 使用CounDownLatch来实现
public class CountDownLatchTest {
    static CountDownLatch c = new CountDownLatch(2);

    public static void main( String[] args ) throws InterruptedException {
        Thread t1 = new Thread(()->{
            c.countDown();
        });

        Thread t2 = new Thread(()->{
           c.countDown();
        });

        t1.start();
        t2.start();
        c.await();
        System.out.println("all parse finish..");

    }
}

CountDownLatch 和 join 的区别

  1. 调用子线程的join方法后,该线程会一直被阻塞直到子线程运行完毕,而CountDownLatch则使用计数器来允许子线程运行完毕或者在运行中递减计数,也就是CountDownLatch可以在子线程运行的 任何 时候让await方法返回而不一定必须等到线程结束。
  2. 使用线程池来管理线程时一般都是直接添加Runable线程池,这时候就没有办法再调用线程的join方法了,就是说countDownLatch相比join方法让我们对线程同步有更灵活的控制。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

半夏_2021

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

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

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

打赏作者

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

抵扣说明:

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

余额充值