乐趣区

关于java:Java多线程如何正确使用倒计时协调器CountDownLatch

前言

本篇文章的代码示例已放到 github 上,Git 地址为:advance(记录每一个学习过程),大家把代码下载下来之后,全局搜寻一些要害代码,即可找到该文章的源码。

大家感觉有用的话,麻烦点个 star👍再走呗!

应用场景

想想一个这样的场景:我要开始吃饭,须要先满足几个先决条件:

  1. 进来买菜
  2. 开始做饭
  3. 把做好的饭端上桌

只有满足这几个条件之后,我能力真正开始吃饭。同时,这里吃饭的人可能不止我一个人,或者还有我的爸爸妈妈等。

CountDownLatch 能够用来实现一个或者多个(留神能够有多个)线程,期待其余线程齐全一组特定的操作后,才开始继续执行的操作,这些特定的操作被称作先决条件。

基本原理

CountDownLatch 外部有一个示意未实现的先决条件的计数器。当某个线程执行 CountDownLatch.await() 时,如果此时的计数器不为 0,那么这个线程就会被阻塞掉。

每当其余线程执行 CountDownLatch.countDown() 时,这个计数器就会被减为 0 时,其余被阻塞的线程就会被主动唤醒,执行后续的操作。

罕用办法

// 结构器,定义计数器的初始值
public CountDownLatch(int count):// 阻塞式期待
public void await()

// 超时主动唤醒式期待
public boolean await(long timeout, TimeUnit unit)

// 计数器减 1,若此时计数器为 0,则期待的那些线程会被唤醒
public void countDown()

// 获取以后计数器的值
public long getCount()

应用示例

定义买菜的异步线程

public class MaiCaiThread implements Runnable{
    private CountDownLatch countDownLatch;
    public MaiCaiThread(CountDownLatch countDownLatch) {this.countDownLatch = countDownLatch;}

    @Override
    public void run() {
        try {TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println("出门买菜回来了");
        countDownLatch.countDown();}
}

定义做饭的异步线程

public class ZuoFanThread implements Runnable{
    private CountDownLatch countDownLatch;

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

    @Override
    public void run() {
        try {TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println("饭做好了");
        countDownLatch.countDown();}
}

定义主线程

public class Main {static CountDownLatch countDownLatch = new CountDownLatch(2);
    public static void main(String[] args) throws InterruptedException {Thread maicai = new Thread(new MaiCaiThread(countDownLatch));
        maicai.start();

        Thread zuoFanThread = new Thread(new ZuoFanThread(countDownLatch));
        zuoFanThread.start();

        System.out.println("我想吃饭了,然而饭还没做好");
        countDownLatch.await();

        System.out.println("程序完结,我吃上饭了");
    }
}

运行后果

注意事项

countDownLatch 的计数器不能循环应用,只能只用一次,若计数器曾经减为 0,后续线程只管调用 await() 办法,也不会失效。

如果要循环应用的话,须要应用 CyclicBarrier。

退出移动版