【Java 并发编程】CountDownLatch 使用场景示例



I CountDownLatch 使用场景举例


1. 单个阻塞等待单个线程 : 初始化 CountDownLatch 时 , 设置其计数为 1 , 在线程 A 中调用 await() 阻塞 , 然后在线程 B 中执行操作 , 之后调用 countDown() 方法 , 计数 - 1 , 线程 A 阻塞解除 ;

2. 单个阻塞等待多个线程 : 初始化 CountDownLatch 时 , 设置其计数为 2 , 在线程 A 中调用 await() 阻塞 ; 然后在线程 B 中执行操作 , 调用 countDown() 方法 , 计数 - 1 ; 同时在线程 C 中执行更长时间的操作 , 调用 countDown() 方法 , 计数 - 1 ; 线程 B 和 C 的操作执行完毕后 , 其计数才减为 0 , 此时线程 A 中的阻塞解除 ;

3. 多个线程阻塞等待单个线程 : 多个线程中调用 CountDownLatch 对象 await() 方法阻塞 , 在另外一个线程中将计数 countDown() 为 0 , 这些线程即可执行 ;

4. 多个线程阻塞等待多个线程 : 多个线程中调用 CountDownLatch 对象 await() 方法阻塞 , 在另外多个线程中将计数 countDown() 为 0 , 被阻塞这些线程即可执行 ;

5. CountDownLatch 使用场景 :

  • ① 单线程等待单线程 : 线程 A 阻塞 , 等待线程 B 执行完毕后 , 在执行线程 A 操作 ;
  • ② 单线程等待多线程 : 线程 A 阻塞 , 等待线程 B , C , D 等线程执行完毕 , 在执行线程 A 操作 ;
  • ③ 单线程与多线程互相阻塞 : 线程 B , C , D , 先被 new CountDownLatch ( 1 ) 对象阻塞住 , 在线程 A 中先解除 B , C , D 的阻塞 , 然后 B , C , D 这三个线程才能继续执行 , 线程 A 解除之后 , 马上被 new CountDownLatch ( 3 ) 对象阻塞 , B , C , D 三个线程执行完后 , 每个线程计数减一 , 之后解除线程 A 阻塞 , 继续执行线程 A 的内容 ;
  • ④ 单线程与多线程互相阻塞并设置超时时间 : 在上述 ③ 情况的基础上 , 加上超时等待 , 如果 B , C , D 线程在指定时间内没有执行完毕 , 那么线程 A 也解除阻塞 , 继续向下执行之后的代码 ;


II CountDownLatch 简单线程阻塞示例


1. 代码说明 : 子线程运行后调用 CountDownLatch 的 await 方法阻塞 , 在主线程中调用 countDown 方法将计数减为 0 , 子线程解除阻塞 ;

2. 代码示例 :

import java.util.concurrent.CountDownLatch;

/**
 * 子线程运行后调用 CountDownLatch 的 await 方法阻塞 ,
 *      在主线程中调用 countDown 方法将计数减为 0 , 子线程解除阻塞
 */
public class CountDownLatchDemo {

    public static void main(String[] args) {

        System.out.println("1. 主线程 : 开始运行 , 创建 CountDownLatch 对象初始计数为 1");

        //创建 CountDownLatch 对象 , 初始计数为 1
        CountDownLatch countDownLatch = new CountDownLatch(1);

        System.out.println("2. 主线程 : 创建子线程并运行");

        //创建子线程 , 并设置其 countDownLatch 对象, 运行子线程
        MyThread myThread = new MyThread(countDownLatch);
        myThread.start();

        System.out.println("3. 主线程 : 调用 countDownLatch.countDown() 方法");
        countDownLatch.countDown();


        System.out.println("4. 主线程 : 运行结束");
    }

    static class MyThread extends Thread{

        /**
         * 用于阻塞的 CountDownLatch 对象
         */
        CountDownLatch countDownLatch;

        /**
         * 主线程中传入 CountDownLatch 对象 , 两个线程公用一个该对象
         * @param countDownLatch
         */
        public MyThread(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            super.run();
            try {
                System.out.println("1. 子线程 : 开始运行 , 并调用 countDownLatch.await() 方法阻塞");

                //阻塞子线程
                countDownLatch.await();

                System.out.println("2. 子线程 : CountDownLatch 对象计数为 0 , 子线程继续运行并结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

}

3. 执行结果 :

1. 主线程 : 开始运行 , 创建 CountDownLatch 对象初始计数为 1
2. 主线程 : 创建子线程并运行
3. 主线程 : 调用 countDownLatch.countDown() 方法
1. 子线程 : 开始运行 , 并调用 countDownLatch.await() 方法阻塞
4. 主线程 : 运行结束
2. 子线程 : CountDownLatch 对象计数为 0 , 子线程继续运行并结束


III CountDownLatch 多个线程联合阻塞示例


1. 情景描述 : 运动员赛跑 , 1 个裁判 , 4 个运动员 , 4 个运动员首先等待裁判发令 , 才能开始跑 , 裁判发令后在终点等待 4 个运动员都达到终点后 , 在宣布成绩 ;

2. 线程模型分析 :

  • ① 线程 : 裁判员是一个单独的线程 , 4 个运动员是 4 个独立的线程 ;
  • ② CountDownLatch : 两种 CountDownLatch 对象 , 一个用于阻塞裁判员线程 , 一个用于阻塞运动员线程 ;
  • ③ 运动员线程 : 四个运动员线程一开始运行后 , 马上调用 new CountDownLatch(1) 对象阻塞住 , 不能向后运行 ;
  • ④ 裁判员线程 : 裁判员线程要等四个运动员线程启动后才能执行 , 先调用 countDown 将四个运动员线程取消阻塞 , 然后调用new CountDownLatch(4) 对象 的 await 阻塞 , 每个运动员线程跑到终点后 , 调用 countDown 方法 , 四个运动员全部到达终点后 , 裁判员解除阻塞 , 宣布成绩 ;

3. 代码示例 :

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

/**
 * 情景描述 : 运动员赛跑 , 1 个裁判 , 4 个运动员 ,
 *      4 个运动员首先等待裁判发令 , 才能开始跑 ,
 *      裁判发令后在终点等待 4 个运动员都达到终点后 , 在宣布成绩 ;
 *
 * 线程模型分析 :
 *
 * ① 线程 : 裁判员是一个单独的线程 , 4 个运动员是 4 个独立的线程 ;
 * ② CountDownLatch : 两种 CountDownLatch 对象 , 一个用于阻塞裁判员线程 , 一个用于阻塞运动员线程 ;
 * ③ 运动员线程 ( 子线程 ) : 四个运动员线程一开始运行后 , 马上调用 new CountDownLatch(1) 对象阻塞住 , 不能向后运行 ;
 * ④ 裁判员线程 ( 主线程 ) : 裁判员线程要等四个运动员线程启动后才能执行 , 先调用 countDown 将四个运动员线程取消阻塞 ,
 *      然后调用new CountDownLatch(4) 对象 的 await 阻塞 , 每个运动员线程跑到终点后 ,
 *      调用 countDown 方法 , 四个运动员全部到达终点后 , 裁判员解除阻塞 , 宣布成绩 ;
 */
public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {

        //用于存储四个运动员的成绩
        int[] grades = new int[4];

        //四个运动员线程的线程池
        ExecutorService executorService = Executors.newCachedThreadPool();

        //阻塞运动员线程的倒计时锁对象 , 需要裁判员线程解锁
        CountDownLatch runnerLatch = new CountDownLatch(1);

        //阻塞裁判线程的倒计时锁对象 , 需要四个运动员线程解锁
        CountDownLatch judgeLatch = new CountDownLatch(4);

        //创建并执行运动员线程 , 使用线程池机制执行
        for(int i = 0; i < 4; i ++){
            int finalI = i;

            //创建运动员线程
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println( finalI + " 号运动员准备完毕 , 等待裁判员发令");
                        runnerLatch.await();
                        System.out.println( finalI + " 号运动员起跑");

                        //设置运动员成绩 , 这里用一个随机数代替
                        grades[finalI] = (int) (Math.random() * 10000);
                        Thread.sleep(grades[finalI]);

                        //通知裁判员到达终点
                        judgeLatch.countDown();
                        System.out.println( finalI + " 号运动员到达终点");

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };

            //使用线程池调度运行该线程
            executorService.execute(runnable);
        }


        System.out.println("裁判员 : 发令 , 起跑");

        //裁判员线程在运动员准备完毕后 , 解除上述 4 个运动员线程的阻塞 , 即运动员起跑
        runnerLatch.countDown();


        System.out.println("裁判员 : 在终点等待 4 名运动员");

        //裁判员线程阻塞, 等待 4 个运动员线程执行完毕
        judgeLatch.await();

        System.out.println("裁判员 : 运动员全部到达终点成绩为 0 号 : " + grades[0] +
                " , 1 号 : " + grades[1] +
                " , 2 号 : " + grades[2] +
                " , 3 号 : " + grades[3]);


    }



}

4. 执行结果 :

裁判员 : 发令 , 起跑
裁判员 : 在终点等待 4 名运动员
2 号运动员准备完毕 , 等待裁判员发令
2 号运动员起跑
1 号运动员准备完毕 , 等待裁判员发令
1 号运动员起跑
0 号运动员准备完毕 , 等待裁判员发令
0 号运动员起跑
3 号运动员准备完毕 , 等待裁判员发令
3 号运动员起跑
1 号运动员到达终点
2 号运动员到达终点
0 号运动员到达终点
3 号运动员到达终点
裁判员 : 运动员全部到达终点成绩为 0 号 : 5601 , 1 号 : 1763 , 2 号 : 4700 , 3 号 : 9650
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CountDownLatchJava并发编程中的一种同步工具类。它的作用是允许一个或多个线程等待其他线程完成操作。CountDownLatch的构造函数接收一个计数值,当计数值变为0时,等待的线程就会被唤醒。使用CountDownLatch可以实现多线程并发编程中的线程协作。 与使用join方法等待多个线程执行完毕不同,CountDownLatch相对灵活。可以通过调用countDown方法来减少计数,唤醒被阻塞的线程。这使得多个线程可以同时进行,并在一定条件下等待其他线程完成后再继续执行。 CountDownLatch一般称为闭锁或计数器,它是Java并发编程中的一种多线程同步工具。它属于AQS(AbstractQueuedSynchronizer)体系的一员,可以实现线程之间的协作和同步操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java多线程之并发工具类](https://download.csdn.net/download/weixin_38713057/13756829)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [java多线程并发之CountDownLatch](https://blog.csdn.net/weixin_42419762/article/details/116220340)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [多线程编程之 CountDownLatch](https://blog.csdn.net/jiangxiayouyu/article/details/118107977)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值