详解Java中CountDownLatch的用法

 更新时间:2023年05月17日 10:39:15   作者:tizzybepeacejoy  
这篇文章主要为大家详细介绍了Java中CountDownLatch类的用法,本文通过一些简单的示例进行了简单介绍,感兴趣的小伙伴可以跟随小编一起了解一下

CountDownLatch使用场景

线程计数器 用于线程执行任务,计数 等待线程结束

用法一: 等待所有的事情都做完

        //程序计数器
        CountDownLatch countDownLatch = new CountDownLatch(10000);
        //2个线程
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        AtomicInteger count = new AtomicInteger(0);
        for (int i = 0; i < 10000; i++) {
            executorService.submit(() -> {
                count.getAndIncrement();//自增
                System.out.println(Thread.currentThread().getName() + " : " + count.get());
                countDownLatch.countDown();
            });
        }
        //线程池 等待10s
        executorService.awaitTermination(10, TimeUnit.SECONDS);
        //关闭线程 其实是将线程状态设置为中断标志  必须等待所有线程处理完任务,才能完全关闭
        executorService.shutdown();
        //必须等待两个线程执行完   会一直等待下去,当然也可以设置指定时间等待超时 await(timeout);
        countDownLatch.await();
    }

始终是2个线程在做事情,等2个线程做完事情才会停止下来。

用法二:假设2个线程做事情,刚开始并行做事情,等一个执行完成之后,另一个才能执行(实际还是计数)

        //程序计数器
        CountDownLatch countDownLatch = new CountDownLatch(1);
        Thread thread1 =new Thread(()->{
                System.out.println(" ---------------- 1  准备 ---------------- ");
                try {
                    countDownLatch.await();
                    System.out.println(" ---------------- 1  finsh  ---------------- ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        });
        thread1.start();
        Thread thread2 = new Thread(() -> {
                System.out.println(" ---------------- 2  准备 ---------------- ");
                try {
                    Thread.sleep(1_000);
                    System.out.println(" ---------------- 异步做事情  ---------------- ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    countDownLatch.countDown();
                }
        });
        thread2.start();
        //main 在等main 结束  死循环
        Thread.currentThread().join();

刚开始一起在准备状态,然后分开做事情

用法三:退出条件

中断一个线程 count 到0

        //程序计数器
        CountDownLatch countDownLatch = new CountDownLatch(1);
        Thread thread = Thread.currentThread();
        Thread thread1 = new Thread(() -> {
            try {
             Thread.sleep(10_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 1 中断条件1
		    countDownLatch.countDown();
        });
        thread1.start();
        countDownLatch.await();
        System.out.println(" ----------------- ");
    }

等待时间中断

        //程序计数器
        CountDownLatch countDownLatch = new CountDownLatch(1);
        Thread thread = Thread.currentThread();
        Thread thread1 = new Thread(() -> {
            try {
             Thread.sleep(10_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread1.start();
        //2 中断条件3
        countDownLatch.await(5, TimeUnit.SECONDS);
        System.out.println(" ----------------- ");
    }

就中断条件而言: 当前还可以父线程中断

        //程序计数器
        Thread thread1 = new Thread(() -> {
            try {
             Thread.sleep(10_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 中断条件3
            thread.interrupt();
        });
        thread1.start();
        System.out.println(" ----------------- ");

用法四: 封装结束完后通知事件

封装结束完后通知事件 参考 CyclicBarrier 通知

public class CountDownLatchTest4 extends CountDownLatch {
    private Runnable runnable;
    public CountDownLatchTest4(int count, Runnable runnable) {
        super(count);
        this.runnable = runnable;
    }
    @Override
    public void countDown() {
        super.countDown();
        if (super.getCount()==0){
            runnable.run();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        //程序计数器
        CountDownLatchTest4 countDownLatch = new CountDownLatchTest4(1,()->{
            System.out.println(" 计数结束 .... ");
        });
        Thread thread1 = new Thread(() -> {
            try {
                Thread.sleep(2_000);
                countDownLatch.countDown();
                System.out.println(" thread 1 do something ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread thread2 = new Thread(() -> {
            try {
                Thread.sleep(1_000);
                System.out.println(" thread 2 do something ");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread1.start();
        thread2.start();
        countDownLatch.await();
        System.out.println("  -----------------  main 结束 ----------------- ");
    }
}

可以看到运行结束,通知事件

自定义计数器

当然我们也可以实现自己的计数器

/**
 * 自定义 CountDown 计数器
 */
public class CountDown {
    //计数器
    private int count = 0;
    private final int total;
    public CountDown(int total) {
        this.total = total;
    }
    public void countDown() {
        synchronized (this) {
            this.count++;
            //锁住 ++ 通知其他线程
            this.notifyAll();
        }
    }
    public void aWait() throws InterruptedException {
        synchronized (this) {
            while (total != count) {
                //不等于 则 继续等待
                this.wait();
            }
        }
    }
}

测试

        CountDown countDown = new CountDown( 5);
        System.out.println(" 准备多线程处理任务 ");
        IntStream.rangeClosed(1, 5).forEach(x -> {
            new Thread(() -> {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(" 线程开始 -----  " + Thread.currentThread().getName());
                countDown.countDown();
            }, x + "").start();
        });
        try {
            countDown.aWait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(" 准备多线程处理任务 结束 ");
        System.out.println(" ---------------------- ");
        System.out.println(" 结束 mian ---------- ");
    }

测试结果

最后

CountDownLatch 可以用来计数,可以测试任务是否执行结束

也可以用来停止一个线程,也可以用来线程运行结束完后通知事件,彼此工作的线程互相独立不关心。

到此这篇关于详解Java中CountDownLatch的用法的文章就介绍到这了,更多相关Java CountDownLatch内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家

相关文章

  • 详解Spring注解 @Configuration

    详解Spring注解 @Configuration

    @Configuration 是 Spring 中的一个注解,它用于标记一个类为配置类,通过配置类可以定义和组装 Spring Bean,并且支持高度灵活的配置方式。本问详细介绍了Spring注解 @Configuration,感兴趣的小伙伴可以参考一下
    2023-04-04
  • java基础之类初始化顺序示例解析

    java基础之类初始化顺序示例解析

    这篇文章主要为大家介绍了java基础之类初始化顺序示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • SpringBoot如何访问html和js等静态资源配置

    SpringBoot如何访问html和js等静态资源配置

    这篇文章主要介绍了SpringBoot如何访问html和js等静态资源配置,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java实现简单的弹球游戏

    Java实现简单的弹球游戏

    这篇文章主要为大家详细介绍了Java实现简单的弹球游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • 如何实现nohup java进程号一直在变方法步骤详解

    如何实现nohup java进程号一直在变方法步骤详解

    这篇文章主要为大家介绍了如何实现nohup java进程号一直在变方法步骤详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Spring-全面详解(学习总结)

    Spring-全面详解(学习总结)

    这篇文章主要介绍了详解Spring框架入门,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能给你带来帮助
    2021-07-07
  • 详解大数据处理引擎Flink内存管理

    详解大数据处理引擎Flink内存管理

    Flink是jvm之上的大数据处理引擎,jvm存在java对象存储密度低、full gc时消耗性能,gc存在stw的问题,同时omm时会影响稳定性。针对频繁序列化和反序列化问题flink使用堆内堆外内存可以直接在一些场景下操作二进制数据,减少序列化反序列化消耗。本文带你详细理解其原理。
    2021-05-05
  • Eclipse/MyEclipse转IntelliJ IDEA完全攻略(图文)

    Eclipse/MyEclipse转IntelliJ IDEA完全攻略(图文)

    这篇文章主要介绍了Eclipse/MyEclipse转IntelliJ IDEA完全攻略(图文),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • 如何取消IDEA中的项目和Git仓库的关联

    如何取消IDEA中的项目和Git仓库的关联

    这篇文章介绍了一种取消已经开启代码控制的项目与Git仓库关联的简单方法,首先,在IntelliJ IDEA中打开项目,删除.idea目录下的vcs.xml文件,这样IDE界面上的Git图标就会消失,接下来,打开项目所在位置,通过文件管理器启用“显示隐藏的项目”选项
    2024-10-10
  • 浅析Java中如何实现线程之间通信

    浅析Java中如何实现线程之间通信

    本篇文章主要介绍了浅析Java中如何实现线程之间通信。针对 Java 的线程间通信进行了大致的讲解,有兴趣的可以了解一下
    2017-04-04

最新评论