JUC:7_2三大辅助类:CylicBarrier原理及使用、线程加法计数器
JUC:7_1三大辅助类:CountDownLatch原理及使用、线程减法计数器
什么是CyclicBarrier?
允许一组线程全部等待彼此达到共同屏障点的同步辅助。 循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。 屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用。
A CyclicBarrier支持一个可选的Runnable命令,每个屏障点运行一次,在派对中的最后一个线程到达之后,但在任何线程释放之前。 在任何一方继续进行之前,此屏障操作对更新共享状态很有用。
通俗的讲: CyclicBarrier,栅栏,等到达到指定个数个等待的线程的时候,一起通过,可以理解为是一个加法计数器。(CyclicBarrier是通过await来计数的,每次await之后,内部通过-1到达0的方式来判断是否触及屏障),
构造方法
CyclicBarrier(int parties)
创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待它时,它将跳闸,并且当屏障跳闸时不执行预定义的动作。
CyclicBarrier(int parties, Runnable barrierAction)
创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待时,它将跳闸,当屏障跳闸时执行给定的屏障动作,由最后一个进入屏障的线程执行。
CountDownLatch 和 CyclicBarrier 的区别:
CountDownLatch 指定线程执行完毕,在执行操作
CyclicBarrier 执行达到指定线程数,再执行操作
虽然两者看上去都是倒计时
但是CyclicBarrier是通过await来计数的(每次await之后,内部通过-1到达0的方式来判断是否触及屏障),
await之后,本次线程会被阻塞, 直到计数器到达,才会执行后面逻辑,类似于葫芦娃救爷爷
代码
package juc.Test3;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 加法计数器:栅栏,等到达到指定个数个等待的线程的时候,一起通过
*/
public class CyclicBarrierDemo {
public static void main(String[] args) {
String[] childs = new String[]{
"大娃(红娃):葫芦七子之首,葫芦七兄弟中的老大,身强力壮,有一身巨大无比的力气,能随意改变身体大小,脾气很好,能够肩负起一个大哥应有的责任",
"二娃(橙娃):橙娃天生拥有一双千里眼和顺风耳,妖怪的一切信息都瞒不住他,并且他的千里眼还能看见隐身中的六娃。聪慧温和、沉着稳重、波澜不惊、坚强无畏、善解人意",
"三娃(黄娃):铜头铁臂,钢筋铁骨,刀枪不入",
"四娃(绿娃):在七个葫芦娃当中排行第四。能吸吐熊熊烈火,炉火纯青,刚阳烈焰。火焰威力巨大,能焚烧世间万物,火气旺盛,还能使用霹雳攻击",
"五娃(青娃):吸水,吐水,口吐闪电产生降雨,弱点:水火不相溶,意气用事",
"六娃(蓝娃):隐身术,透体术,来无影去无踪,聪明机灵,最善于偷盗和行动",
"七娃(紫娃):最小,没有大本领,倍受哥哥们的关爱,有宝葫芦,可以吸入魔法、兵器和妖怪"
};
CyclicBarrier cyclicBarrier = new CyclicBarrier(childs.length, () -> {
System.out.println("七个葫芦娃了,可以去救爷爷了!");
});
for (int i = 0; i < childs.length; i++) {//i局部变量存在栈,new Thred存在堆
final int temp = i;//jdk1.8有优化,不加final修饰,也会自动识别为final,但是规范上还是要写
new Thread(() -> {//Lambda表达式本质是一个类,因此相当于是匿名内部类,无法获取类的局部变量,只能操作全局变量,需要final进行修饰才能获得
// System.out.println(Thread.currentThread().getName() + i + "落地了。");
System.out.println(Thread.currentThread().getName() + temp + "的葫芦落地了,是" + childs[temp] + "。");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}, "树枝").start();
}
/**
* 成员变量的生命周期更长,
* 当成员变量中引用了局部变量,那么就需要加final,复制一份到堆内存中,
* 否则引用的该变量就访问不到了
*
* 加final,变量会存在堆中的方法区里,子线程共享进程的堆,所以能读到
* 否则是存在另一个线程的栈中,不同线程读不到
*
*
* CountDownLatch 和 CyclicBarrier 的区别:
* 虽然两者看上去都是倒计时
* 但是CyclicBarrier是通过await来计数的(每次await之后,内部通过-1到达0的方式来判断是否触及屏障),
* await之后,本次线程会被阻塞,
* 直到计数器到达,才会执行后面的救爷爷
*/
/**
*
* 输出结果:
* 树枝1的葫芦落地了,是二娃(橙娃):橙娃天生拥有一双千里眼和顺风耳,妖怪的一切信息都瞒不住他,并且他的千里眼还能看见隐身中的六娃。聪慧温和、沉着稳重、波澜不惊、坚强无畏、善解人意。
* 树枝0的葫芦落地了,是大娃(红娃):葫芦七子之首,葫芦七兄弟中的老大,身强力壮,有一身巨大无比的力气,能随意改变身体大小,脾气很好,能够肩负起一个大哥应有的责任。
* 树枝2的葫芦落地了,是三娃(黄娃):铜头铁臂,钢筋铁骨,刀枪不入。
* 树枝3的葫芦落地了,是四娃(绿娃):在七个葫芦娃当中排行第四。能吸吐熊熊烈火,炉火纯青,刚阳烈焰。火焰威力巨大,能焚烧世间万物,火气旺盛,还能使用霹雳攻击。
* 树枝6的葫芦落地了,是七娃(紫娃):最小,没有大本领,倍受哥哥们的关爱,有宝葫芦,可以吸入魔法、兵器和妖怪。
* 树枝4的葫芦落地了,是五娃(青娃):吸水,吐水,口吐闪电产生降雨,弱点:水火不相溶,意气用事。
* 树枝5的葫芦落地了,是六娃(蓝娃):隐身术,透体术,来无影去无踪,聪明机灵,最善于偷盗和行动。
* 七个葫芦娃了,可以救爷爷!
*/
}
}