线程安全(九)CyclicBarrier

系列文章目录

线程安全(一)java对象头分析以及锁状态
线程安全(二)java中的CAS机制
线程安全(三)实现方法sychronized与ReentrantLock(阻塞同步)
线程安全(四)Java内存模型与volatile关键字
线程安全(五)线程状态和线程创建
线程安全(六)线程池
线程安全(七)ThreadLocal和java的四种引用
线程安全(八)Semaphore
线程安全(九)CyclicBarrier
线程安全(十)AQS(AbstractQueuedSynchronizer)

0.前言

CyclicBarrier:障碍器类,意为循环栅栏。也是JUC的工具类,依靠Condition和ReetrantLock实现了屏障功能,当所有子任务执行完成,屏障解除,下一任务才会继续,而且屏障会恢复。

1.源码解析

1.1.属性

   // 可重入锁
    private final ReentrantLock lock = new ReentrantLock();
    /** Condition to wait on until tripped */
    // 条件
    private final Condition trip = lock.newCondition();
    /** The number of parties */
    // 参与的线程数量
    private final int parties;
    /* The command to run when tripped */
    // 当等待进入屏障数为0时,执行
    private final Runnable barrierCommand;
    /** The current generation */
    // 当前代
    private Generation generation = new Generation();
    // 正在等待进入屏障的线程数量
    private int count;

1.2.构造方法

  // 屏障接触,执行barrierAction
  public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }
    // 无barrierAction
    public CyclicBarrier(int parties) {
        this(parties, null);
    }

1.3.核心方法

当执行await方法时,和之前的带条件Condition的ReentrantLock 一样,会获取条件锁,当正在等待进入屏障数为0前,一直阻塞等待,等到为0时,执行barrierAction,并调用singleAll()方法

/**
     * 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;
            // 计数器为0时,执行指定任务,唤醒拦截的所有线程
            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();
        }
    }

2.示例

2.1.测试

public class Test9_CyclicBarrier {

    private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    private static final CyclicBarrier cyclicBarrier = new CyclicBarrier(4);

    public static void main(String[] args) {
        String[] nameArray = {"一", "二", "三", "四", "五", "六", "七"};//非整数倍栅栏数
        for (int i = 0; i < nameArray.length; i++) {
            Runnable t1 = new TaskThread(cyclicBarrier, nameArray[i]);
            threadPool.execute(t1);
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadPool.shutdown();;
    }

    static class TaskThread implements Runnable {
        private String name;
        private CyclicBarrier barrier;

        public TaskThread(CyclicBarrier barrier, String name) {
            this.barrier = barrier;
            this.name = name;
        }

        @Override
        public void run() {
            try {
                Thread.currentThread().setName(name);
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " 到达栅栏");
                barrier.await();
                System.out.println(Thread.currentThread().getName()  + " 冲破栅栏");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

在这里插入图片描述必选是整数倍栅栏数才可以关闭线程池,其他线程都处于await。

2.2.赛马

public class HorseRace implements Runnable {

    private static final int FINISH_LINE = 75;
    private static List<Horse> horses = new ArrayList<>();
    private static ExecutorService exec = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(7, new HorseRace());
        for (int i = 0; i < 7; i++) {
            Horse horse = new Horse(barrier);
            horses.add(horse);
            exec.execute(horse);
        }
    }

    @Override
    public void run() {
        StringBuilder s = new StringBuilder();
        //打印赛道边界
        for (int i = 0; i < FINISH_LINE; i++) {
            s.append("=");
        }
        System.out.println(s);
        //打印赛马轨迹
        for (Horse horse : horses) {
            System.out.println(horse.tracks());
        }
        //判断是否结束
        for (Horse horse : horses) {
            if (horse.getStrides() >= FINISH_LINE) {
                System.out.println(horse + "won!");
                exec.shutdownNow();
                return;
            }
        }
        //休息指定时间再到下一轮
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("barrier-action sleep interrupted");
        }
    }

    static class Horse implements Runnable {
        private static int counter = 0;
        private final int id = counter++;
        private int strides = 0;
        private int result;
        private static Random rand = new Random(47);
        private static CyclicBarrier barrier;

        public Horse(CyclicBarrier b) {
            barrier = b;
        }

        @Override
        public void run() {
            try {
                while (!Thread.interrupted()) {
                    //赛马每次随机跑几步
                    strides += rand.nextInt(7);
                    barrier.await();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public String tracks() {
            StringBuilder s = new StringBuilder();
            for (int i = 0; i < getStrides(); i++) {
                s.append("*");
            }
            s.append(id);
            return s.toString();
        }

        public synchronized int getStrides() {
            return strides;
        }

        @Override
        public String toString() {
            return "Horse " + id + " ";
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值