JAVA高并发编程 - CountDownLatch 使用(一)

81 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情

简介

CountDownLatch 是通过一个计数器来实现的,计数器的初始值为 线程的数量 。每当一个线程执行完成后,计数器的值 -1 ,当值为 0 时,表示所有线程执行完毕。

计数器count是闭锁需要等待的线程数量,只能被设置一次,且CountDownLatch没有提供任何机制去重新设置计数器count。

与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。

其他N个线程必须引用CountDownLatch闭锁对象,因为它们需要通知CountDownLatch对象,它们各自完成了任务;这种通知机制是通过CountDownLatch.countDown()方法来完成的;每调用一次,count的值就减1,因此当N个线程都调用这个方法,count的值就等于0,然后主线程就可以通过await()方法,恢复执行自己的任务。

使用场景

1.执行某个任务前完成各自任务,比如在返回前端数据前,一些多线程任务必须完成。

2.死锁检测:用N个线程去访问共享资源,在每个测试阶段线程数量不同,并尝试产生死锁。

使用例子

作为场景第一种 - 执行某个任务前完成各自任务

代码示例

main 方法

public class CountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
            new Thread(new Worker(startSignal, doneSignal)).start();
        }
        System.out.println("zhunbei bobo");
        startSignal.countDown();
        System.out.println("henhen bobo");
        doneSignal.await();
        System.out.println("bobo wanbi");
    }
}

线程方法

public class Worker implements Runnable{
    private final CountDownLatch startSignal;
    private final CountDownLatch doneSignal;
​
    Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }
​
    @Override
    public void run() {
        try {
            //调用await()方法的线程会被挂起,等待直到count值为0再继续执行。
            startSignal.await();
            go();
            //线程执行完毕 -1
            doneSignal.countDown();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
​
    void go() {
        System.out.println("liuyi bobo !");
    }
}

输出结果

zhunbei bobo
henhen bobo
liuyi bobo !
liuyi bobo !
liuyi bobo !
liuyi bobo !
liuyi bobo !
liuyi bobo !
liuyi bobo !
liuyi bobo !
liuyi bobo !
liuyi bobo !
bobo wanbi

可见主线程在 await() 后的代码,需要等待 work 线程方法全部执行完毕后,才执行。

好了,今日学习到这里了,有点太晚了,另一个场景的代码例子我们明天再实现,晚安。