1.简单使用
public class CyclicBarrierTest implements Runnable{
CyclicBarrier cyclicBarrier;
public CyclicBarrierTest(CyclicBarrier cyclicBarrier ) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
Thread.sleep(200);
System.out.println(Thread.currentThread().getName()+"到达栅栏 A");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName()+"冲破栅栏 A");
Thread.sleep(500);
System.out.println(Thread.currentThread().getName()+"到达栅栏 B");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName()+"冲破栅栏 B");
} catch (Exception e) {
// TODO: handle exception
}
}
}
@Test
public void testCyclicBarrier(){
int threadNum = 3;
CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum);
CyclicBarrierTest cyclicBarrierTest = new CyclicBarrierTest(cyclicBarrier);
for(int i = 0 ; i < threadNum; i++){
new Thread(cyclicBarrierTest,"线程:"+i).start();
}
try {
System.out.println("主线程休眠。。。");
Thread.sleep(5000);
System.out.println("主线程启动...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2.源码层面
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
也就是说本质上调用的是dowait方法,下面是dowait方法的源码
/**
* Main barrier code, covering the various policies.
*/
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
在提出问题前,先了解 lock 一波
参考https://www.cnblogs.com/lemon-flm/p/7880119.html
-
lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
-
tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
-
tryLock(long timeout,TimeUnit unit),如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
-
lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断
以下问题来源于 :https://www.oschina.net/question/1861827_2274671
这里存在几个问题:
- ReentrantLock锁为什么要定义一个final的临时变量来使用,而不是直接使用this.lock?
答:主要是因为为了确保可见性,this.lock是volatile类型,在使用时会需要刷新缓存变量直内存,在频繁使用时有性能损耗。所以用临时变量接管,可以提高性能。另外一个原因,对于lock,在方法内的后续操作中是不允许有修改的,所以会定义一个final类型的临时变量,其实也就是有点相当于注释的作用了 - 此方法是多个线程中调用的,调用此方法表示到达了屏障位置,并且每个线程调用此方法的时候都是需要通过计数来判断是否全都到达屏障位置。但方法开始就加了锁,而计数是在锁范围内的代码执行的,也就是说应该是只有第一个调用的线程才会执行计数,而后调用的所有线程都应该是拿不到锁的,那这个计数是怎么实现的呢?
答:因为锁有是否重入的分类,刚好ReentrantLock是重入锁。