CountDownLatch用法、详解

目录

​编辑

概述:

应用场景:

优点:

缺点:

主要方法:

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`可以有效地实现线程之间的同步和协调。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
CountDownLatch是Java中的一个同步工具类,用于控制多个线程的执行顺序。它通过一个计数器来实现,该计数器初始化为一个正整数,每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器的值减到0时,所有等待的线程就会被唤醒继续执行。 在Android中,CountDownLatch可以用于等待多个异步操作完成后再执行某个任务,或者等待多个线程都达到某个状态后再继续执行。 下面是CountDownLatch的基本使用方法: 1. 创建CountDownLatch对象,并指定计数器的初始值。 ```java CountDownLatch latch = new CountDownLatch(3); // 计数器初始值为3 ``` 2. 在需要等待的地方调用`await()`方法,使当前线程进入等待状态,直到计数器值为0时才会继续执行。 ```java try { latch.await(); // 等待计数器值为0 } catch (InterruptedException e) { e.printStackTrace(); } ``` 3. 在需要通知其他线程继续执行的地方调用`countDown()`方法,将计数器的值减1。 ```java latch.countDown(); // 计数器减1 ``` 下面是一个简单的示例,演示了如何使用CountDownLatch等待多个线程完成后再执行某个任务: ```java import java.util.concurrent.CountDownLatch; public class CountDownLatchExample { public static void main(String[] args) { final CountDownLatch latch = new CountDownLatch(3); for (int i = 0; i < 3; i++) { final int threadNum = i; new Thread(() -> { try { Thread.sleep(1000); System.out.println("Thread " + threadNum + " completed."); latch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } try { latch.await(); System.out.println("All threads completed. Start executing the task..."); // 执行任务 } catch (InterruptedException e) { e.printStackTrace(); } } } ``` 在上面的示例中,我们创建了一个初始值为3的CountDownLatch对象。然后创建了3个线程,每个线程会在执行完任务后将计数器减1。主线程调用`await()`方法等待计数器的值变为0,当所有线程都执行完任务后,主线程才会继续执行并输出"All threads completed. Start executing the task..."。 希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一百减一是零

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

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

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

打赏作者

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

抵扣说明:

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

余额充值