一、CountDownLatch
1、CountDownLatch一般用于在做某件事A之前,必须要完成另外一批事情,所以事件A必须阻塞在那
2、例如:
(1)、excel导出
多个sheet页数据填充,每个sheet页可以看做一个线程
主线程就是excel文件流输出
(2)、需要重多个三方接口请求数据,组装输出
请求每个三方接口就时一个线程
主线程就是从结果中取数据组装
3、代码实现6个小孩出门之后,老师(主线程)锁门
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
System.out.println("child:" + Thread.currentThread().getName()+" Go out");
countDownLatch.countDown(); // 数量-1
},String.valueOf(i)).start();
}
countDownLatch.await(); // 等待计数器归零,然后再向下执行
System.out.println("teacher close door");
}
当然,CountDownLatch也可以用来阻塞一批线程
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("child:" + Thread.currentThread().getName()+" Go out");
countDownLatch.countDown(); // 数量-1
},String.valueOf(i)).start();
}
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
try {
countDownLatch.await(); // 等待计数器归零,然后再向下执行
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("teacher close door");
},String.valueOf(i)).start();
}
// countDownLatch.await(); // 等待计数器归零,然后再向下执行
// System.out.println("teacher close door");
}
二、CyclicBarrier
CyclicBarrier与CountDownLatch类似,也可以实现做某件事A之前,必须要完成另外一批事情
但是CyclicBarrier强调的是这一批线程达到某一个屏障,也就是阻塞在那里
(Barrier:障碍;屏障;隔阂;关卡;阻力;分界线;难以逾越的数量(或水平、数目))
代码实现王者荣耀十人加载之后才能开启游戏
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{
System.out.println("全军出击");
});
for (int i = 1; i <=10 ; i++) {
final int temp = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "玩家"+ temp+"号已经加载100%"); // 局部内部类只能访问常量,所以转成temp
try {
cyclicBarrier.await(); // 等待
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
看到这里,大家可能觉得跟CountDownLatch没啥区别,我们继续看
王者荣耀开局十个人加载,每个人的加载过程就是一个线程,其中某一个人加载好了,并不能直接开打,得等到十个人都加载好了,才能开打
public static void main(String[] args) {
/**
* 王者荣耀加载
*/
CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{
System.out.println("全军出击");
});
for (int i = 1; i <=10 ; i++) {
final int temp = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "玩家"+ temp+"号已经加载100%"); // 局部内部类只能访问常量,所以转成temp
try {
cyclicBarrier.await(); // 等待
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"玩家"+ temp+"号已经不可阻挡!!");
}).start();
}
}
可以看到每个线程达到屏障那里就直接等待在那了,等所有人加载好了,才能开打,当然CyclicBarrier的构造器也可以只传一个数字,不需要再多一个Runnable的实现类,可以理解为十名玩家都加载到100%之后,就直接开打了,不需要系统来喊全军出击了。
个人理解CountDownLatch主要是用于阻塞另外一个或者另外一批线程,而CyclicBarrier主要是用于阻塞自己这一批线程。