1、CountDownLatch概述
1.1、CountDonLatch情景模拟
在讲CountDownLatch的应用场景之前,我们先在现实生活中,找到一个对应的场景。例如班主任带一帮孩子去春游,春游回家前,班主任需要清点人数,确保每个小孩都上车,才能发车回家。
1.2、CountDonLatch 简介
CountDonLatch 让一个线程持续等待,直到其他多线程执行的一组操作全部完成以后,这些等待的线程才会继续执行。
CountDownLatch,是JDK1.5的java.util.concurrent并发包中提供的一个并发工具类。所谓CountDown即 倒计时 的意思,所谓Latch即 门闩 的意思。所以综合起来,CountDownLatch指的就是 倒计时门闩。
1.3、CountDonLatch 常用方法
(1)getCount()
获取当前count的值,创建CountDonLatch时设置,班主任需要知道多少小孩参加了春游。
(2)await()
await():让当前线程等待此CountDownLatch对象的count变为0,可以中断。
(3)await(timeout,TimeUnit)
让当前线程等待此CountDownLatch对象的count变为0,可以超时、可以中断。
(4)countDown
使此CountDownLatch对象的count值减1(无论执行多少次,count最小值为0)。
2、CountDownLatch 应用案例
2.1 模拟班主任等学生
package lzf.juc;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
/**
* @author Java小工匠
*/
public class CountDownLatchTest01 {
public static void main(String[] args) throws InterruptedException {
// 和班主任来的一个5个学生
CountDownLatch latch = new CountDownLatch(5);
for (int index = 1; index <= 5; index++) {
final int tempIndex = index;
new Thread(() -> {
// 模拟学生到达约定地点的时间
int num = new Random().nextInt(10);
String msg = "等待第" + tempIndex + "个学生" + num + "秒!";
System.out.println(msg);
try {
Thread.sleep(num * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 学生到达约定地点时间
latch.countDown();
String emsg = "第" + tempIndex + "个学生到达!";
System.out.println(emsg);
}).start();
}
// 班主任等待开始
long start = System.currentTimeMillis();
latch.await();
System.out.println("学生全部到达!");
// 班主任 等待结束
long end = System.currentTimeMillis();
System.out.println("班主任等待:" + (end - start) / 1000 + "秒!");
}
}
数据结果
2.2 模拟等待超时
假如在学生,游玩的过程中,第五个同学偷偷跑回家,大家都傻傻的在等他,如果用 await 方法,班主任就需要一直等待下去,大家永远回不了家。所以出现了 await(timeout,TimeUnit) ,班主任可以设定等待的最大时间,即使人员不到齐,在等待超过设定时间,一样发车回家。
代码实现
package lzf.juc;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* @author Java小工匠
*/
public class CountDownLatchTest02 {
public static void main(String[] args) throws InterruptedException {
// 和班主任来的一个5个学生
CountDownLatch latch = new CountDownLatch(5);
for (int index = 1; index <= 5; index++) {
final int tempIndex = index;
new Thread(() -> {
if (tempIndex != 5) {
// 模拟学生到达约定地点的时间
int num = new Random().nextInt(10);
String msg = "等待第" + tempIndex + "个学生" + num + "秒!";
System.out.println(msg);
try {
Thread.sleep(num * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 学生到达约定地点时间
latch.countDown();
String emsg = "第" + tempIndex + "个学生到达!";
System.out.println(emsg);
} else {
System.out.println("第5个学生偷偷跑回家了!");
}
}).start();
}
// 班主任等待开始
long start = System.currentTimeMillis();
// 傻傻的一直等待
// latch.await();
// 设置等待最才时间
boolean b = latch.await(10, TimeUnit.SECONDS);
if (b) {
System.out.println("学生全部到达!");
} else {
long count = latch.getCount();
System.out.println("学生还有" + count + "个未到达,等待超时!");
}
// 班主任 等待结束
long end = System.currentTimeMillis();
System.out.println("班主任等待:" + (end - start) / 1000 + "秒!");
}
}
运行结果
2.3 模拟多个时间集合
学生出去游玩,早上集合、中午吃饭、晚上集合 都需要班主任点名与等待。那么该如何开发这个程序呢!
package lzf.juc;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
/**
* @author Java小工匠
*/
public class CountDownLatchTest03 {
public static void main(String[] args) throws InterruptedException {
// 早上集合等待
CountDownLatch alatch = new CountDownLatch(5);
// 中午集合等待
CountDownLatch blatch = new CountDownLatch(5);
// 晚上集合等待
CountDownLatch clatch = new CountDownLatch(5);
for (int index = 1; index <= 5; index++) {
final int tempIndex = index;
new Thread(() -> {
// 早上
int anum = new Random().nextInt(5);
try {
Thread.sleep(anum * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
alatch.countDown();
String amsg = "早上:第" + tempIndex + "个学生到达!";
System.out.println(amsg);
// 中午
int bnum = new Random().nextInt(5) + 5;
try {
Thread.sleep(bnum * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
blatch.countDown();
String bmsg = "中午:第" + tempIndex + "个学生到达!";
System.out.println(bmsg);
// 晚上
int cnum = new Random().nextInt(5) + 5;
try {
Thread.sleep(cnum * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
clatch.countDown();
String cmsg = "晚上:第" + tempIndex + "个学生到达!";
System.out.println(cmsg);
}).start();
}
// 班主任等待开始
alatch.await();
System.out.println("早上==========");
blatch.await();
System.out.println("中午==========");
clatch.await();
System.out.println("晚上==========");
}
}
运行结果
3.4 多个时间点集合,依赖关系
调整3.3程序中的,中午和晚上的随机数值不加5 秒.
int bnum = new Random().nextInt(5) ;
int cnum = new Random().nextInt(5) ;
完整代码
package lzf.juc;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
/**
* @author Java小工匠
*/
public class CountDownLatchTest03 {
public static void main(String[] args) throws InterruptedException {
// 早上集合等待
CountDownLatch alatch = new CountDownLatch(5);
// 中午集合等待
CountDownLatch blatch = new CountDownLatch(5);
// 晚上集合等待
CountDownLatch clatch = new CountDownLatch(5);
for (int index = 1; index <= 5; index++) {
final int tempIndex = index;
new Thread(() -> {
// 早上
int anum = new Random().nextInt(5);
try {
Thread.sleep(anum * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
alatch.countDown();
String amsg = "早上:第" + tempIndex + "个学生到达!";
System.out.println(amsg);
// 中午
int bnum = new Random().nextInt(5) + 5;
try {
Thread.sleep(bnum * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
blatch.countDown();
String bmsg = "中午:第" + tempIndex + "个学生到达!";
System.out.println(bmsg);
// 晚上
int cnum = new Random().nextInt(5) + 5;
try {
Thread.sleep(cnum * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
clatch.countDown();
String cmsg = "晚上:第" + tempIndex + "个学生到达!";
System.out.println(cmsg);
}).start();
}
// 班主任等待开始
alatch.await();
System.out.println("早上==========");
blatch.await();
System.out.println("中午==========");
clatch.await();
System.out.println("晚上==========");
}
}
运行结果
调整代码的等待时间,会发现老师在早上的集合点,还没有等待所有人员到齐,行动迅速同学已经在早、中、晚的集合点转了一圈,这样显然不合理。CountDownLatch这个工具类,无法解决这样的诉求,我们将在后续博客文章中,为您寻找解决方案。
如果读完觉得有收获的话,欢迎点赞、关注、加公众号【小工匠技术圈】
个人公众号,欢迎关注,查阅更多精彩历史!