java并发工具类学习之CountDownLatch

本文介绍了Java中CountDownLatch的用法,它允许线程等待其他线程完成操作。以解析Excel多个sheet数据为例,说明可使用多线程解析,用CountDownLatch等待所有解析完成。还提到其构造器、countDown和await方法,以及带指定时间的await方法,同时给出使用注意事项。

CountDownlatch允许一个线程或者多个线程等待其他线程完成操作。

假如有这样一个需求:

  我们需要解析一个Excel里面的多个sheet的数据,此时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有sheet都解析完了,程序需要提示解析完成。

使用CountDownLatch实现如下:

import java.util.concurrent.CountDownLatch;

/**
 * @Description
 * @Author DJZ-WWS
 * @Date 2019/5/27 14:57
 */
public class TestCountDownLatch {


    static CountDownLatch countDownLatch = new CountDownLatch(2);

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("第一个sheet解析完毕");
            //没调用一次这个方法,构造器里的初始值就会减一
            countDownLatch.countDown();

        }).start();
        new Thread(() -> {

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("第二个sheet解析完毕");
            //没调用一次这个方法,构造器里的初始值就会减一
            countDownLatch.countDown();

        }).start();

        System.out.println("主线开始等待");
        countDownLatch.await();
        System.out.println("所有的sheet解析完毕,继续执行后面的操作");
    }
}

执行结果如下:

CountDownLatch的构造器接收一个int型的参数作为计数器,如果你想等待N个点完成,这里就传入N。

当我们调用CountDownLatch的countDown方法时,N就会减一,他的await方法会阻塞当前线程,直到N变成0。

由于countDown方法可以用在任何地方,这里说的N个点,可以是N个线程,也可以是1个线程里面的N个操作。用在多线程时,只需要把这个CountdownLatch的引用传递到线程里即可。

如果解析某个sheet的线程处理的比较慢,我们不可能让主线程一直等待,所有可以使用另外一个带指定时间的await方法-await(long time,TimeUnit  unit)

注意计数器必须大于等于0,只是等于0的时候计数器就是0.调用await方法时不会阻塞当前线程。countDownLatch不可能重新初始化或者修改CountDownLatch内部的计数器的值。

下面是另一个类似的例子:

package juc.currnet;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Description 该程序用来模拟发送命令与执行命令,主线程代表指挥官,新建3个线程代表战士,战士一直等待着指挥官下达命令,
 * *若指挥官没有下达命令,则战士们都必须等待。一旦命令下达,战士们都去执行自己的任务,指挥官处于等待状态,战士们任务执行完毕则报告给
 * @Author DJZ-WWS
 * @Date 2019/4/13 15:25
 */
public class CountDownLatchTest {


    public static void main(String[] args) {

        ExecutorService service = Executors.newCachedThreadPool();
        //模拟命令
        CountDownLatch cdOrder = new CountDownLatch(1);
        //模拟战士,多个线程

        CountDownLatch answer = new CountDownLatch(3);

        for (int i = 0; i < 3; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        //战士待命状态
                        System.out.println("线程" + Thread.currentThread().getName() + "正在准备待命");
                       //个人理解,到目前为止还没有向线程池提交任务,等待的线程为主xianc
                        cdOrder.await();
                        System.out.println("线程" + Thread.currentThread().getName() + "已接受命令");
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("线程" + Thread.currentThread().getName() + "回应命令处理结果");

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        answer.countDown();
                    }
                }
            };
            service.execute(runnable);//为线程池添加任务

        }

        try {
            Thread.sleep((long) (Math.random() * 10000));
            System.out.println("线程" + Thread.currentThread().getName() + "即将发布命令");
            cdOrder.countDown(); //发送命令,cdOrder减1,处于等待的战士们停止等待转去执行任务。
            System.out.println("线程" + Thread.currentThread().getName() + "已发送命令,正在等待结果");
            answer.await(); //命令发送后指挥官处于等待状态,一旦cdAnswer为0时停止等待继续往下执行
            System.out.println("线程" + Thread.currentThread().getName() + "已收到所有响应结果");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }
        service.shutdown(); //任务结束,停止线程池的所有线程
    }

}

结果如下:

现在依旧记得刚刚来这家公司的时候我组长面试问的我这个类,我记得我当时举了一个例子:

模拟一家人去吃饭,人去的时候不确定,必须等到人到齐的时候才可以吃饭,这个时候就可以使用这个工具类。当时我是这么答得,也没有再继续往下问了。

参考:《java并发编程的艺术》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值