java CyclicBarrier

**特性:**可重用 ,恢复初始状态有两种方式 ,一种是直接调用reset方法,一种是await通过后内部会自动重置

结构:

  1. 一个栅栏状态记录器Generation,记录栅栏是否被破坏
  2. 一个全局锁ReentrantLock对象
  3. 一个全局锁绑定的通信器Condition对象
  4. 一个上限线程数parties
  5. 一个回调接口Runnable对象barrierCommand
  6. 一个计数器count

栅栏原理:

  1. 初始化一个CyclicBarrier对象,构造器中需要包含parties与一个Runnable回调 ,回调可以为空
  2. 每次调用CyclicBarrier对象的await方法,内部调用了直接dowait方法
  3. 获取全局锁
  4. count减一
  5. count结果为0 -> barrierCommand不为空则直接调用起run方法 -> 发送信号通知其他线程 -> count恢复为parties并且创建一个新状态记录器,若是中间出现异常则直接设置栅栏为破坏状态
  6. count不为0 -> 调用lock锁的的await方法进行等待 ,收到通知后发现状态记录器已经更新则安全通过,若是发生线程中断也设置栅栏为破坏状态并继续抛异常

应用示例

public class Demo {
	public static void main(String[] args) {
		CyclicBarrier cy = new CyclicBarrier(2, ()-> {
			System.out.println("+++++++栅栏冲破");
		});
		for(int i =0; i < 10;i++) {
			int t = i;
			new Thread(()->{
				try {
					Thread.sleep(1000 * t);
					System.out.println("线程" + t +"到达");
					cy.await();
					System.out.println("线程" + t +"冲过");
				} catch (InterruptedException | BrokenBarrierException e) {
					e.printStackTrace();
				}
			}).start();
		}
	}
}

运行结果:
线程0到达
线程1到达
+++++++栅栏冲破
线程1冲过
线程0冲过
线程2到达
线程3到达
+++++++栅栏冲破
线程3冲过
线程2冲过
线程4到达
线程5到达
+++++++栅栏冲破
线程5冲过
线程4冲过
线程6到达
线程7到达
+++++++栅栏冲破
线程7冲过
线程6冲过
线程8到达
线程9到达
+++++++栅栏冲破
线程9冲过
线程8冲过

成员变量

	//全局锁
    private final ReentrantLock lock = new ReentrantLock();
    /** 通知队列 */
    private final Condition trip = lock.newCondition();
    /** 线程数目统计 */
    private final int parties;
    /*冲破栅栏的回调线程*/
    private final Runnable barrierCommand;
    /** The current generation */
    private Generation generation = new Generation();
    //累计数 每次调用await就减1  重置后恢复parties
    private int count;

构造方法:

public CyclicBarrier(int parties)

/**
*	parties 线程数量
*	barrierAction 线程冲破后的回调
*/
public CyclicBarrier(int parties, Runnable barrierAction)

主要方法

await

 public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen;
        }
    }

awai方法内部直接调用的是dowait,超时后直接抛出Error。
dowait源码有点长,耐心看

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;
           //累计数count减到0 标识栅栏前的线程数目已经达到上限  可以放行了
           if (index == 0) {  // tripped
               boolean ranAction = false;
               try {
                   final Runnable command = barrierCommand;
                   if (command != null)
                   //发现回调类  直接调用run方法,使用当前线程执行
                       command.run();
                   ranAction = true;
                   //回调检查并执行完毕后通知栅栏前其他等待的线程可以继续执行了
                   nextGeneration();
                   return 0;
               } finally {
                   if (!ranAction)
                       breakBarrier();
               }
           }

            // loop until tripped, broken, interrupted, or timed out
            for (;;) {
                try {
                   //没有设置超时时间直接调用 ReentrantLock 的await方法
                    if (!timed)
                        trip.await();
                       //设置了超时时间后调用ReentrantLock 的await(time)方法
                    else if (nanos > 0L)  
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                   //发生中断异常后 若当前栅栏状态不是破坏状态则直接设置为破坏状态 再继续外抛异常
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
						//栅栏状态已经改变,可能是其他线程修改了栅栏状态 恢复当前线程的中断
                        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();
        }
    }

await()方法会阻塞当前线程,直到运行到此处的方法达到上限,需要注意的是该方法可能会抛出多种异常,并且抛出后仅影响当前线程,不影响CyclicBarrier继续使用,但若是线程是有状态的,例如线程总数刚好够用,那么除去抛出异常的线程数后总数可能就不够了,可能会造成整体死掉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值