详解Java中CountDownLatch的用法
作者: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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家