CountdownLatch(门闩)

CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。

 

CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。
当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在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 可以用来计数,可以测试任务是否执行结束
也可以用来停止一个线程,也可以用来线程运行结束完后通知事件,彼此工作的线程互相独立不关心。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

time Friend

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

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

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

打赏作者

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

抵扣说明:

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

余额充值