内容简介:为了能够理解CountDownLatch,举一个很通俗的例子,运动员进行跑步比赛时,假设有6个运动员参与比赛,裁判员在终点会为这6个运动员分别计时,可以想象每当一个运动员到达终点的时候,对于裁判员来说就少了一个计时任务。直到所有运动员都到达终点了,裁判员的任务也才完成。这6个运动员可以类比成6个线程,当线程调用CountDownLatch.countDown方法时就会对计数器的值减一,直到计数器的值为0的时候,裁判员(调用await方法的线程)
1.背景:
2.概念
- countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
- 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
3.使用场景
example1
为了能够理解CountDownLatch,举一个很通俗的例子,运动员进行跑步比赛时,假设有6个运动员参与比赛,裁判员在终点会为这6个运动员分别计时,
可以想象每当一个运动员到达终点的时候,对于裁判员来说就少了一个计时任务。直到所有运动员都到达终点了,裁判员的任务也才完成。这6个运动员可
以类比成6个线程,当线程调用CountDownLatch.countDown方法时就会对计数器的值减一,直到计数器的值为0的时候,裁判员(调用await方法的线程)
才能继续往下执行。
下面来看些CountDownLatch的一些重要方法。
先从CountDownLatch的构造方法看起:
public CountDownLatch(int count)
构造方法会传入一个整型数N,之后调用CountDownLatch的 countDown 方法会对N减一,知道N减到0的时候,当前调用 await 方法的线程继续执行。
CountDownLatch的方法不是很多,将它们一个个列举出来:
1. await() throws InterruptedException:调用该方法的线程等到构造方法传入的N减到0的时候,才能继续往下执行;
2. await(long timeout, TimeUnit unit):与上面的await方法功能一致,只不过这里有了时间限制,调用该方法的线程等到指定的timeout时间后,不管N是
否减至为0,都会继续往下执行;
3. countDown():使CountDownLatch初始值N减1;
4. long getCount():获取当前CountDownLatch维护的值;
下面用一个具体的例子来说明CountDownLatch的具体用法:
package com.example.demo.test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * * @version V1.0 15:44 guozl * @since 1.0 */ public class CountDownLatchDemo { private static CountDownLatch startSignal = new CountDownLatch(1); //用来表示裁判员需要维护的是6个运动员 private static CountDownLatch endSignal = new CountDownLatch(6); public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(6); for (int i = 0; i < 6; i++) { executorService.execute(() -> { try { System.out.println(Thread.currentThread().getName() + " 运动员就位等待裁判员响哨!!!"); startSignal.await(); System.out.println(Thread.currentThread().getName() + "正在全力冲刺"); System.out.println(Thread.currentThread().getName() + " 到达终点"); } catch (InterruptedException e) { e.printStackTrace(); }finally { endSignal.countDown(); } }); } Thread.sleep(1000); System.out.println("裁判员发号施令啦!!!"); startSignal.countDown(); endSignal.await(); System.out.println("所有运动员到达终点,比赛结束!"); executorService.shutdown(); } } 输出结果: pool-1-thread-2 运动员就位等待裁判员响哨!!! pool-1-thread-1 运动员就位等待裁判员响哨!!! pool-1-thread-4 运动员就位等待裁判员响哨!!! pool-1-thread-3 运动员就位等待裁判员响哨!!! pool-1-thread-5 运动员就位等待裁判员响哨!!! pool-1-thread-6 运动员就位等待裁判员响哨!!! 裁判员发号施令啦!!! pool-1-thread-2正在全力冲刺 pool-1-thread-2 到达终点 pool-1-thread-3正在全力冲刺 pool-1-thread-3 到达终点 pool-1-thread-4正在全力冲刺 pool-1-thread-4 到达终点 pool-1-thread-5正在全力冲刺 pool-1-thread-5 到达终点 pool-1-thread-1正在全力冲刺 pool-1-thread-1 到达终点 pool-1-thread-6正在全力冲刺 pool-1-thread-6 到达终点 所有运动员到达终点,比赛结束!
该示例代码中设置了两个CountDownLatch,第一个 endSignal 用于控制让main线程(裁判员)必须等到其他线程(运动员)让CountDownLatch维护的
数值N减到0为止。另一个 startSignal 用于让main线程对其他线程进行“发号施令”,startSignal引用的CountDownLatch初始值为1,而其他线程执行的
run方法中都会先通过 startSignal.await() 让这些线程都被阻塞,直到main线程通过调用 startSignal.countDown(); ,将值N减
1,CountDownLatch维护的数值N为0后,其他线程才能往下执行,并且,每个线程执行的run方法中都会通
过 endSignal.countDown(); 对 endSignal 维护的数值进行减一,由于往线程池提交了6个任务,会被减6次,所以 endSignal 维护的值最终会变为0,
因此main线程在 latch.await(); 阻塞结束,才能继续往下执行。
另外,需要注意的是,当调用CountDownLatch的countDown方法时,当前线程是不会被阻塞,会继续往下执行,比如在该例中会继续输出 pool-1-
thread-4 到达终点 。
example2
模拟数据量较大 多线程分页查询处理
package com.example.demo.test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * CountDownLatch 的使用示例 * @version V1.0 10:51 guozl * @since 1.0 */ public class CountDownLatchExample { // 请求的数量(每页数量) private static final int threadCount = 8; public static void main(String[] args) throws InterruptedException { //定义j为页数 for (int j = 1; j < 3; j++) { ExecutorService threadPool = Executors.newFixedThreadPool(5); final CountDownLatch countDownLatch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { final int threadnum = i; threadPool.execute(() -> {// Lambda 表达式的运用 try { //实际业务操作 test(threadnum); } catch (InterruptedException e) { e.printStackTrace(); } finally { countDownLatch.countDown();// 表示一个请求已经被完成 } }); } countDownLatch.await(); threadPool.shutdown(); System.out.println("finish"); } System.out.println("all finish"); System.out.println("处理所有数据业务操作"); } public static void test(int threadnum) throws InterruptedException { Thread.sleep(500);// 模拟请求的耗时操作 System.out.println("threadnum:" + threadnum); Thread.sleep(500);// 模拟请求的耗时操作 } } 执行结果: threadnum:4 threadnum:2 threadnum:3 threadnum:0 threadnum:1 threadnum:7 threadnum:6 threadnum:5 finish threadnum:2 threadnum:4 threadnum:0 threadnum:1 threadnum:3 threadnum:7 threadnum:6 threadnum:5 finish all finish 处理所有数据业务操作
下一篇分享循环栅栏:CyclicBarrier 并与CountDownLatch做比较 有问题欢迎评论区交流 共同进步。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据结构与问题求解
韦斯 / 清华大学出版社 / 2011-8 / 89.50元
《数据结构与问题求解(Java语言版)(第4版)》是专为计算机科学专业的两个学期课程而设计的,从介绍什么足数据结构开始,继而对高级数据结构与算法进行分析。《数据结构与问题求解(Java语言版)(第4版)》以独特的方式,清晰地将每种数据结构的接口与其实现分离开来,即将如何使用数据结构与如何对数据结构编程相分离。《数据结构与问题求解(Java语言版)(第4版)》从抽象思维和问题求解的角度出发,为数据结......一起来看看 《数据结构与问题求解》 这本书的介绍吧!