CountDownLatch用法、详解

文章介绍了Java并发包中的CountDownLatch,用于控制线程执行顺序,支持等待多个线程完成后再行动。它具有简单接口和灵活性,但是一旦计数器归零,无法重置。通过案例分析了其应用场景和使用方法。
摘要由CSDN通过智能技术生成

目录

​编辑

概述:

应用场景:

优点:

缺点:

主要方法:

1. `CountDownLatch(int count)`:

2. `void await()`:

3. `boolean await(long timeout, TimeUnit unit)`:

4. `void countDown()`:

案例:

1、猴哥吃蕉====await()

执行结果:

分析:

2、猴哥吃蕉====await(5, TimeUnit.SECONDS);

执行结果

分析:

总结:


概述:

`CountDownLatch`是Java并发包中的一个同步工具类,用于控制线程的执行顺序和协调多个线程之间的操作。它通过一个计数器来实现,计数器的初始值由用户指定,每当一个线程完成了特定任务或达到了某个状态,计数器的值就会减少。当计数器的值变为0时,等待`CountDownLatch`的线程将被释放。

应用场景:

`CountDownLatch`常用于以下场景:

1. 主线程等待多个子线程完成任务后再继续执行。

2. 多个线程等待某个共享资源就绪后再同时开始执行。

3. 控制多个线程按照特定的顺序执行。

优点:

1. 简单易用:`CountDownLatch`提供了简单的接口,易于使用和理解。

2. 灵活性:可以根据实际需求设置等待的线程数量,可以灵活地控制线程的执行顺序和协调多个线程之间的操作。

缺点:

1. 一次性:`CountDownLatch`的计数器只能减少到0,一旦减少到0后,无法重置计数器,因此只能使用一次。

2. 无法逆转:一旦计数器的值减少到0,等待线程将被释放,无法再次等待。

主要方法:

1. `CountDownLatch(int count)`:

构造函数,用于创建一个`CountDownLatch`对象,并指定需要等待的线程数量。

2. `void await()`:

使当前线程等待,直到`count`值减少到0。它会阻塞当前线程,直到所有线程都调用了`countDown()`方法,如果`count`值已经为0,则该方法立即返回。

3. `boolean await(long timeout, TimeUnit unit)`:

方法与`await()`方法类似,但它还接受一个超时时间参数。使当前线程等待,直到`count`值减少到0或超过指定的超时时间。如果在超时时间内`count`值变为0,则返回`true`;如果超过超时时间仍未达到0,则返回`false`。

4. `void countDown()`:

将`count`值减少1。当某个线程完成了特定任务或达到了某个状态时,应调用此方法来减少`count`值。

案例:

1、猴哥吃蕉====await()



import java.util.concurrent.CountDownLatch;

/**
 * 猴哥
 */
public class MonkeyBanana extends Thread {
    CountDownLatch countDownLatch;
    String name;

    public MonkeyBanana(String name, CountDownLatch countDownLatch) {
        this.name = name;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        System.out.println(name + "开始吃香蕉");
        try {
            long l = (long) (Math.random() * 10000);
            Thread.sleep(l);
            if (l / 1000 == 0) {
                System.out.println(name + "简直不要太厉害了,跟我们表演了一波一口闷香蕉!");
            } else if (l / 1000 > 0 && l / 1000 < 5) {
                System.out.println(name + "在" + l / 1000 + "秒内吃完了香蕉!");
            } else if (l / 1000 == 5) {
                System.out.println(name + "在最后1秒内吃完了香蕉!");
            } else if (l / 1000 > 5) {
                System.out.println(name + "在" + l / 1000 + "秒内吃完了香蕉,已超时!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            countDownLatch.countDown();//线程倒数器-每次都会减1
        }
    }
}

import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class CountDownLatchTest {

    public static void main(String[] args) {
        monkeyEatAwait();
    }


    /**
     * 猴哥吃香蕉
     */
    public static void monkeyEatAwait() {
        try {
            //倒数器记数
            CountDownLatch downLatch = new CountDownLatch(1);
            System.out.println("猴哥吃香蕉大赛预备::");
            //倒数3个数
            for (int i = 3; i > 0; i--) {
                System.out.println("倒数 : " + i);
                TimeUnit.SECONDS.sleep(1);
            }
            downLatch.countDown();
            downLatch.await();
            System.out.println("BOOM 开始!");
            //几个猴哥再比赛
            int monkeyNum = 5;//需要等待的线程数量。也就是说,这些线程执行完之后才会往下继续走
            CountDownLatch countDownLatch = new CountDownLatch(monkeyNum);
            for (int i = 0; i < monkeyNum; i++) {
                new MonkeyBanana("猴哥" + (i + 1), countDownLatch).start();
            }
            //等待所有猴哥都吃完香蕉
            countDownLatch.await();
            System.out.println("所有猴哥都吃完了香蕉!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
执行结果:

分析:

这个是等待所有猴哥都吃完香蕉。也就是所有的子线程任务都走完之后才会走主线程,执行主线程方法。

2、猴哥吃蕉====await(5, TimeUnit.SECONDS);

import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class CountDownLatchTest {

    public static void main(String[] args) {
        monkeyEatAwaitPar();
    }

    /**
     * 猴哥吃香蕉
     */
    public static void monkeyEatAwaitPar() {
        try {
            //倒数器记数
            CountDownLatch downLatch = new CountDownLatch(1);
            System.out.println("猴哥吃香蕉大赛预备::");
            //倒数3个数
            for (int i = 3; i > 0; i--) {
                System.out.println("倒数 : " + i);
                TimeUnit.SECONDS.sleep(1);
            }
            downLatch.countDown();
            downLatch.await();
            System.out.println("BOOM 开始!");
            //几个猴哥再比赛
            int monkeyNum = 5;//需要等待的线程数量。也就是说,这些线程执行完之后才会往下继续走
            CountDownLatch countDownLatch = new CountDownLatch(monkeyNum);
            for (int i = 0; i < monkeyNum; i++) {
                new MonkeyBanana("猴哥" + (i + 1), countDownLatch).start();
            }
            //超时判断
            boolean await = countDownLatch.await(5, TimeUnit.SECONDS);
            //超过5秒结束比赛
            if (!await) {
                System.out.println("时间到!");
            } else {
                System.out.println("所有猴哥都吃完了香蕉!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
执行结果

分析:

这里我们用了带入参的await方法,判断如果吃香蕉时间超出5秒钟,则算是失败!可以处理特殊情况下线程卡死,超时等状态。

总结:

`CountDownLatch`是一个非常有用的同步工具,适用于需要等待多个线程完成任务或达到某个状态后再继续执行的场景。它简单易用,但只能使用一次且无法逆转。在合适的场景下,使用`CountDownLatch`可以有效地实现线程之间的同步和协调。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一百减一是零

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

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

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

打赏作者

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

抵扣说明:

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

余额充值