一、cyclicBarrier简介
CyclicBarrier允许N个线程相互等待。
让一组线程到达一个屏障,只有最后一个线程执行完后,屏障开放,cyclicBarrier指定的线程才开始执行,放行条件=线程数
CountDownLatch区别cyclicBarrier
CountDownLatch :执行await()等待其它子线程执行完 , 放行条件>= 子线程数, 也就是说可以有多于count的线程对CountDownLatch 执行count+1操作,只要countdown次数>=count, awati()就是唤醒; countdown是外部其它工作线程扣减
cyclicBarrier:多个线程相互等待, 放行条件=线程数 ,那么执行cyclicBarrier指定的线程;cyclicBarrier由相互控制
CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重 置。所以CyclicBarrier能处理更为复杂的业务场景。例如,如果计算发生错误,可以重置计数 器,并让线程重新执行一次。
基本使用
//启动主方法
public static void main(String[] args){
final int ROWS=10000;
final int NUMBERS=1000;
final int SEARCH=5;
final int PARTICIPANTS=5;
final int LINES_PARTICIPANT=2000;
MatrixMock mock=new MatrixMock(ROWS, NUMBERS,SEARCH);
Results results=new Results(ROWS);
Grouper grouper=new Grouper(results,mock.getDatas());
//需要等待5个线程执行完,执行grouper
final CyclicBarrier barrier=new CyclicBarrier(PARTICIPANTS,grouper);
Searcher searchers[]=new Searcher[PARTICIPANTS];
for (int i=0; i<PARTICIPANTS; i++){
if(i==PARTICIPANTS-1){
searchers[i]=new Searcher(i*LINES_PARTICIPANT, (i*LINES_PARTICIPANT)+LINES_PARTICIPANT-1, mock, results, 5,barrier);
}else{
searchers[i]=new Searcher(i*LINES_PARTICIPANT, (i*LINES_PARTICIPANT)+LINES_PARTICIPANT-1, mock, results, 5,barrier);
}
Thread thread=new Thread(searchers[i]);
thread.start();
}
System.out.printf("Main: The main thread has finished.\n");
}
public class Searcher implements Runnable {
private int firstRow;
private int lastRow;
private MatrixMock mock;
private Results results;
private int number;
private final CyclicBarrier barrier;
public Searcher(int firstRow, int lastRow, MatrixMock mock, Results results, int number, CyclicBarrier barrier) {
this.firstRow = firstRow;
this.lastRow = lastRow;
this.mock = mock;
this.results = results;
this.number = number;
this.barrier = barrier;
}
@Override
public void run() {
//do something
}
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
二、主要方法
1、构造方法
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
// parties表示“必须同时到达barrier的线程个数”。
this.parties = parties;
// count表示“处在等待状态的线程个数”。
this.count = parties;
// barrierCommand表示“parties个线程到达barrier时,会执行的动作”。
this.barrierCommand = barrierAction;
}
count计数器初始化,表示需要等待count个线程执行完
2、等待方法
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen;
}
}
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
// 获取“独占锁(lock)”
lock.lock();
try {
// 保存“当前的generation”
final Generation g = generation;
// 若“当前generation已损坏”,则抛出异常。
if (g.broken)
throw new BrokenBarrierException();
// 如果当前线程被中断,则通过breakBarrier()终止CyclicBarrier,唤醒CyclicBarrier中所有等待线程。
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
// 将“count计数器”-1
int index = --count;
// 如果index=0,则意味着“有parties个线程到达barrier”。
if (index == 0) { // tripped
boolean ranAction = false;
try {
// 如果barrierCommand不为null,则执行该动作。
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
// 唤醒所有等待线程,并更新generation。
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// 当前线程一直阻塞,直到“有parties个线程到达barrier” 或 “当前线程被中断” 或 “超时”这3者之一发生,
// 当前线程才继续执行。
for (;;) {
try {
// 如果不是“超时等待”,则调用await()进行等待;否则,调用awaitNanos()进行等待。
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
// 如果等待过程中,线程被中断,则执行下面的函数。
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
Thread.currentThread().interrupt();
}
}
// 如果“当前generation已经损坏”,则抛出异常。
if (g.broken)
throw new BrokenBarrierException();
// 如果“generation已经换代”,则返回index。
if (g != generation)
return index;
// 如果是“超时等待”,并且时间已到,则通过breakBarrier()终止CyclicBarrier,唤醒CyclicBarrier中所有等待线程,并抛出TimeoutException异常
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
// 释放“独占锁(lock)”
lock.unlock();
}
}
等待方法,将count计数器-1
,判断if(index==0)
表明count个线程已经执行完,if action is not null
,执行action线程
dowait通过lock实现作用就是让当前线程阻塞,直到“有parties个线程到达barrier” 或 “当前线程被中断” 或 “超时”这3者之一发生,当前线程才继续执行。
三、总结CyclicBarrier执行流程,countdown执行流程
CyclicBarrier是由ReentrantLock可重入锁和Condition共同实现的。
CyclicBarrier
构造方法: 初始化“必须同时到达barrier的线程个数”。
CyclicBarrier dowait方法: 当一个线程执行完自己的逻辑后,执行dowait()方法,第一:用lock.lock获取锁,将count计数器-1
,
如果count不为0,那么调用condition.await()方法阻塞 ,释放锁。
当最后一个线程执行到dowait方法将index减到0后,
判断if(index==0)
表明count个线程已经执行完,if action is not null
,执行action线程,唤醒所有condition对象上等待的线程,新建一个generation对象
countdown:
构造方法: 初始化计数器个数count个,
wait()方法: 自旋 --> 判断计数器==0, 为0 返回,否则阻塞
countDown方法: 计数器减一,唤醒阻塞的线程