CyclicBarrier
的字面意思是可循
环
使用(
Cyclic
)的屏障(
Barrier
)。它要做的事情是,
让
一
组线
程到达一个屏障(也可以叫同步点)
时
被阻塞,直到最后一个
线
程到达屏障
时
,屏障才会
开
门
,所有被屏障
拦
截的
线
程才会
继续
运行。
一种同步辅助工具,允许一组线程都等待对方到达一个共同的障碍点。CyclicBarrier在涉及固定大小的线程组的程序中很有用,这些线程有时必须互相等待。该屏障被称为循环屏障,因为它可以在释放等待的线程后重新使用
介绍CyclicBarrier2种构造器的使用
package com.netty.obj.demo5.d2;
import java.util.concurrent.CyclicBarrier;
/**
* @PackageName:com.netty.obj.demo5.d2 Description
* @author:
* @date:2022/1/12
*/
public class CyclicBarrierTest {
static CyclicBarrier c = new CyclicBarrier(2);
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
try {
c.await();
} catch (Exception e) {
}
System.out.println(1);
}
}).start();
try {
c.await();
} catch (Exception e) {
}
System.out.println(2);
}
}
CyclicBarrier
默
认
的构造方法是
CyclicBarrier
(
int parties
),其参数表示屏障
拦
截的
线
程数
量,每个
线
程
调
用
await
方法告
诉
CyclicBarrier
我已
经
到达了屏障,然后当前
线
程被阻塞。
输出结果:因
为
主
线
程和子
线
程的
调
度是由
CPU
决定的,两个
线
程都有可能先
执
行
![](https://i-blog.csdnimg.cn/blog_migrate/8da6ffc6b5c8896663ad88d2e5ff6043.png)
如果把
new CyclicBarrier(2)
修改成
new CyclicBarrier(3)
,
则
主
线
程和子
线
程会永
远
等待,
因
为
没有第三个
线
程
执
行
await
方法,即没有第三个
线
程到达屏障,所以之前到达屏障的两个
线
程都不会
继续执
行。
CyclicBarrier
还
提供一个更高
级
的构造函数
CyclicBarrier
(
int parties
,
Runnable barrier-
Action
),用于在
线
程到达屏障
时
,
优
先
执
行
barrierAction
,方便
处
理更复
杂
的
业务场
景
package com.netty.obj.demo5.d2;
import java.util.concurrent.CyclicBarrier;
/**
* @PackageName:com.netty.obj.demo5.d2 Description
* @author:
* @date:2022/1/12
*/
public class CyclicBarrierTest2 {
static CyclicBarrier c = new CyclicBarrier(2, new A());
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
try {
c.await();
} catch (Exception e) {
}
System.out.println(1);
}
}).start();
try {
c.await();
} catch (Exception e) {
}
System.out.println(2);
}
static class A implements Runnable {
@Override
public void run() {
System.out.println(3);
}
}
}
输出结果:
因
为
CyclicBarrier
设
置了
拦
截
线
程的数量是
2
,所以必
须
等代
码
中的第一个
线
程和
线
程
A
都
执
行完之后,才会
继续执
行主
线
程,然后
输
出
2
![](https://i-blog.csdnimg.cn/blog_migrate/747fec0720a6bf48e23f96658a4a231a.png)
CyclicBarrier的应用场景:
CyclicBarrier
可以用于多
线
程
计
算数据,最后合并
计
算
结
果的
场
景。例如,用一个
Excel
保
存了用
户
所有
银
行流水,每个
Sheet
保存一个
账户
近一年的每笔
银
行流水,
现
在需要
统计
用
户
的日均
银
行流水,先用多
线
程
处
理每个
sheet
里的
银
行流水,都
执
行完之后,得到每个
sheet
的日
均
银
行流水,最后,再用
barrierAction
用
这
些
线
程的
计
算
结
果,
计
算出整个
Excel
的日均
银
行流
水。
package com.netty.obj.demo5.d2;
import java.util.Map;
import java.util.concurrent.*;
/*** 银行流水处理服务类 ** @authorftf **/
public class BankWaterService implements Runnable {
/*** 创建4个屏障,处理完之后执行当前类的run方法 */
private CyclicBarrier c = new CyclicBarrier(4, this);
/*** 假设只有4个sheet,所以只启动4个线程 */
private Executor executor = Executors.newFixedThreadPool(4);
/*** 保存每个sheet计算出的银流结果 */
private ConcurrentHashMap<String, Integer> sheetBankWaterCount = new ConcurrentHashMap<String, Integer>();
private void count() {
for (int i = 0; i < 4; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
// 计算当前sheet的银流数据,计算代码省略
sheetBankWaterCount.put(Thread.currentThread().getName(), 1);
// 银流计算完成,插入一个屏障
try {
c.await();
} catch (InterruptedException |
BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}
}
@Override
public void run() {
int result = 0;
// 汇总每个sheet计算出的结果
for (Map.Entry<String, Integer> sheet : sheetBankWaterCount.entrySet()) {
result += sheet.getValue();
}
// 将结果输出
sheetBankWaterCount.put("result", result);
System.out.println(result);
}
public static void main(String[] args) {
BankWaterService bankWaterCount = new BankWaterService();
bankWaterCount.count();
}
}
使用
线
程池
创
建
4
个
线
程,分
别计
算每个
sheet
里的数据,每个
sheet
计
算
结
果是
1
,再由
BankWaterService
线
程
汇总
4
个
sheet
计
算出的
结
果。
CyclicBarrier
和
CountDownLatch
的区
别
CountDownLatch
的
计
数器只能使用一次,而
CyclicBarrier
的
计
数器可以使用
reset()
方法重
置。所以
CyclicBarrier
能
处
理更
为
复
杂
的
业务场
景。例如,如果
计
算
发
生
错误
,可以重置
计
数
器,并
让线
程重新
执
行一次。
总结:此案例来源于《Java并发编程艺术》,通过学习本书增加对CyclicBarrier的理解,作为笔记加深理解