CyclicBarrier 例子:
/**
* 实现功能是将goodsReqDtoList作为calcEstimateAmount方法的入参,然后将最终的结果放入map中进行返回
* 1.根据 goodsReqDtoList 的长度,判断我们要开多少个线程
* 2.将每个线程获得的结果放入 map 中,等到所有线程都计算完,将结果进行返回
* @param goodsReqDtoList CommonGoodsReqDto,支持多个商品属性的查询
* @return
*/
@Override
public Map<String, Long> getRebatePlanAmount(List<CommonGoodsReqDto> goodsReqDtoList) {
// 线程执行数量,判断要开多少个线程执行
int threadNum;
int everyListCount = 5; // 每个list中有5条数据
if (goodsReqDtoList.size() % everyListCount == 0) {
threadNum = goodsReqDtoList.size() / everyListCount;
} else {
threadNum = goodsReqDtoList.size() / everyListCount + 1;
}
final Map<String, Long> resMap = new ConcurrentHashMap<>();
final CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum);
List<CommonGoodsReqDto> goodsList = new ArrayList<>();
for (int i = 0; i < goodsReqDtoList.size(); i++) {
goodsList.add(goodsReqDtoList.get(i));
if ((i == goodsReqDtoList.size() - 1) || (i + 1) % everyListCount == 0) {
final List list = goodsList;
new Thread(new Runnable() {
@Override
public void run() {
// 将每个线程获得的结果放到 resMap 中
resMap.putAll(calcEstimateAmount(list));
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("AAA");
}
}).start();
}
if ((i + 1) % everyListCount == 0) {
goodsList = new ArrayList<>();
}
}
return resMap;
}
源码分析:
https://www.cnblogs.com/leesf456/p/5392816.html
二、CyclicBarrier数据结构
分析源码可以知道,CyclicBarrier底层是基于ReentrantLock和AbstractQueuedSynchronizer来实现的,所以,CyclicBarrier的数据结构也依托于AQS的数据结构,在前面对AQS的分析中已经指出了其数据结构,在这里不再累赘。
执行过程如下:
1.首先使用ReentrantLock加锁
lock.lock();
2.获取当前generation
3.判断如果屏障 被破坏,就抛出异常BrokenBarrierException
4. 判断如果线程被中断,调用breakBarrier损坏屏障,并且唤醒所有的线程,同时抛出线程中断异常
5.int index = --count; 减少正在等待进入屏障的线程的数量,也就是代表增加了已进入线程的屏障数量
6.如果index==0,代表所有线程都进入了屏障,开始运行对应的command,调用command.run()
7.然后进入下一代 nextGeneration
8.进入for无限循环,如果没有设置等待时间,就 trip.await();进行等待;如果设置了等待时间,
就trip.awaitNanos(nanos);等待一段时间;await()底层是调用LockSupport.park() 锁住
死循环终止的条件:屏障broken,线程中断interrupted,或者超时
countdowlatch 和 cyclicbarrier 的内部原理和用法,以及相互之间的差别。
CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它运行一个或者多个线程一直处于等待状态。
CyclicBarrier要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。
CyclicBarrier初始化的时候,设置一个屏障数。线程调用await()方法的时候,这个线程就会被阻塞,当调用await()的线程数量到达屏障数的时候,主线程就会取消所有被阻塞线程的状态。
前者是递减,不可循环,后者是递加,可循环用
countdowlatch 基于abq cb基于ReentrantLock Condition