首发于靳刚同学

理解CyclicBarrier

认识CyclicBarrier

CyclicBarrier也叫同步屏障,循环栅栏(后续专门讲解"循环"),可以让一组线程到达屏障时被阻塞,直到最后一个线程到达后,他们一起被执行.

CyclicBarrier好比一扇门,默认情况下关闭状态,直到所有线程都就位,门才打开,使其通行,

源码分析

public class CyclicBarrier {
    private static class Generation {
        boolean broken = false;
    }
    private final ReentrantLock lock = new ReentrantLock();

    private final Condition trip = lock.newCondition();

    private final int parties;
    
    private int count

    private final Runnable barrierCommand;

    private Generation generation = new Generation();
    ...
}

下面介绍下CyclicBarrier的字段

  • lock: CyclicBarrier是基于ReentrantLock实现的
  • Generation :代,栅栏的年代/年龄
  • generation线程全部就位,栅栏每次打开 或者 栅栏重置reset后,年代改变
  • trip:lock上的Condition条件,当线程未全部就位时,到达栅栏的线程将被添加到该条件队列
  • parties 常量,代表线程的数量,在构造时传入,当前就位线程数(count)==parties时,栅栏打开
  • count 当前就位的线程数.当count==parties时,栅栏打开
  • barrierCommand command线程,在所有线程就位之后且未被唤醒 期间 执行

构造方法

  1. CyclicBarrier(int parties),
  2. CyclicBarrier(int parties, Runnable barrierAction)

介绍完字段,一起看await核心实现(doawait(false,oL)):

    /**
     * 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();
        }
    }


  1. 准备工作:


当一个线程到达时,首先看generation是否被破坏,如果没被破坏,检查当前线程是否中断,如果中断,则该线程无法就位,这组线程将全部不能执行,执行breakBarrier()

2. 内部变量count减1,如果count等于0,调用command线程的run,并且执行nextGeneration();

其中nextGeneration()方法使得栅栏可循环使用:

a. 唤醒所以就位线程

b. 重新设置栅栏 :count恢复为parties,重新生成Generation对象,赋值给generation


3. 如果count不等于0,说明有线程还未到屏障处,则在锁条件变量trip上等待。

接下来看看nextGeneration方法

private void nextGeneration() {
// signal completion of last generation
    trip.signalAll();
// set up next generation
    count = parties;
generation = new Generation();
}

到这里,CyclicBarrier的原理已经就介绍完了,最后看下它的应用场景.

应用场景

假设我们程序员小组(20个人)要去体检,当所有程序员就位后,一同出发

Programmer.java :每个运动员都就位后才开始。

class Programmer implements Runnable {

    private CyclicBarrier cyclicBarrier;
    private String name;

    public Programmer(CyclicBarrier cyclicBarrier, String name) {
        this.cyclicBarrier = cyclicBarrier;
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + "就位");
        try {
            cyclicBarrier.await();
            System.out.println(time + ": "+ new Date());
        } catch (Exception e) {
        }
    }
}

HealthCheck.java : 负责屏障的初始化。

class HealthCheck {
    private CyclicBarrier cyclicBarrier = new CyclicBarrier(20);
    public void start() {
        List<Programmer> programmers  = new ArrayList<>();
        for (int i=0;i<20;i++){
              programmers.add(new Programmer(cyclicBarrier,"programmer"+"-"+i));
        }
        Executor executor = Executors.newFixedThreadPool(8);
        for (Programmer programmer : programmers) {
            executor.execute(programmer);
        }
    }
}

编辑于 2019-02-20 15:29