Sike java source synchronous series CyclicBarrier resolved - there are pictures and the truth

problem

What (1) CyclicBarrier that?

(2) CyclicBarrier have what characteristics?

(3) Comparison with CyclicBarrier CountDownLatch of?

Brief introduction

CyclicBarrier, loop fence, it will block a set of threads until the threads reach a certain condition before continuing execution. It is very similar to CountDownLatch, but different, CountDownLatch need to call countDown () method trigger events, and CyclicBarrier No, it's like a fence, like when a group of threads have reached the barrier at just continue to go down.

Instructions

public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);

        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                System.out.println("before");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println("after");
            }).start();
        }
    }
}    

This method is very simple, using a CyclicBarrier making three threads to keep pace, when three threads simultaneously arrive cyclicBarrier.await();at all run down together.

Source code analysis

The main inner class

private static class Generation {
    boolean broken = false;
}

Generation, the Chinese translation for generations, a generation of generations, CyclicBarrier cycle for control use.

For example, in the above example after the completion of three threads into the next generation, the thread continues to wait for three reached again performed together at the fence, and CountDownLatch can not do this, CountDownLatch disposable, which can not be reset times.

The main property

// 重入锁
private final ReentrantLock lock = new ReentrantLock();
// 条件锁,名称为trip,绊倒的意思,可能是指线程来了先绊倒,等达到一定数量了再唤醒
private final Condition trip = lock.newCondition();
// 需要等待的线程数量
private final int parties;
// 当唤醒的时候执行的命令
private final Runnable barrierCommand;
// 代
private Generation generation = new Generation();
// 当前这一代还需要等待的线程数
private int count;

Can be seen through the property, inside CyclicBarrier is achieved by reentrant lock condition of the lock, then you can make the brain look at this scene it?

Tong brother to mend Brain: If the initial time count = parties = 3, when the first thread reaches the barrier, count minus 1, then it is added to the queue Condition, reaches the wire at the second thread is true, the third thread reaches the barrier office, count reduced to 0, calling Condition of signalAll () to inform the other two threads, and then add them to the AQS queue, waiting for the current thread has finished running, calling lock.unlock () when waking up from AQS order queue a thread continues to run, that is in fact the first three threads in order (queue) arrives at the fence, in turn run down.

More than purely Tong brother brain supplement the content, the truth is that it is not so, and look back.

Construction method

public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    // 初始化parties
    this.parties = parties;
    // 初始化count等于parties
    this.count = parties;
    // 初始化都到达栅栏处执行的命令
    this.barrierCommand = barrierAction;
}

public CyclicBarrier(int parties) {
    this(parties, null);
}

Constructor parties need to pass a variable, which is the number of threads to wait.

await () method

Each thread needs to wait at the fence of the need to explicitly call await () method waits for the arrival of other threads.

public int await() throws InterruptedException, BrokenBarrierException {
    try {
        // 调用dowait方法,不需要超时
        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();
    try {
        // 当前代
        final Generation g = generation;
        
        // 检查
        if (g.broken)
            throw new BrokenBarrierException();

        // 中断检查
        if (Thread.interrupted()) {
            breakBarrier();
            throw new InterruptedException();
        }
        
        // count的值减1
        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();
            }
        }

        // 这个循环只有非最后一个线程可以走到
        for (;;) {
            try {
                if (!timed)
                    // 调用condition的await()方法
                    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();

            // 正常来说这里肯定不相等
            // 因为上面打破栅栏的时候调用nextGeneration()方法时generation的引用已经变化了
            if (g != generation)
                return index;
            
            // 超时检查
            if (timed && nanos <= 0L) {
                breakBarrier();
                throw new TimeoutException();
            }
        }
    } finally {
        lock.unlock();
    }
}
private void nextGeneration() {
    // 调用condition的signalAll()将其队列中的等待者全部转移到AQS的队列中
    trip.signalAll();
    // 重置count
    count = parties;
    // 进入下一代
    generation = new Generation();
}

dowait () method in the entire logic into two parts:

(1) the last thread to go above logic, when the count is reduced to zero, breaking the fence, it calls nextGeneration () method notifies the waiting thread queue condition is transferred to AQS queue waiting to be awakened, and into the next generation.

(2) not the last thread to go below for loop logic, the thread blocks method at the condition of the await (), which will be added to condition the queue, waiting to be notified when they wake-up has been updated change "generation" , and this time returned.

Diagram

CyclicBarrier

Studied previous chapters, look at this chart is very simple, do not understand the students also need to take a look at the recommended content oh ^ ^

to sum up

(1) CyclicBarrier make a set of threads blocked in await () at Wake when the last thread arrives (just queue conditions to move from AQS queue) in front of the thread we continue to go down;

(2) CyclicBarrier than directly using a AQS synchronizer implemented;

(3) CyclicBarrier achieve synchronization logic based on the whole and for condition Condition ReentrantLock;

Egg

CyclicBarrier similarities and differences with the CountDownLatch?

(1) both can achieve blocked a group of threads waiting to be awakened;

(2) The former is the last thread automatic wake-up upon arrival;

(3) the latter is achieved by explicitly calling the countDown ();

(4) The former is achieved by re-lock the lock and conditions, which are directly implemented based AQS;

(5) The former has the concept of "generation", can be reused, which can only be used once;

(6) The former can only achieve multiple threads reach the barrier at run together;

(7) the latter can be achieved not only a thread multiple threads wait condition is satisfied, but also to achieve a thread waiting for multiple threads conditions are satisfied (see the chapter CountDownLatch use cases);

Recommended Reading

1, Sike java synchronization of the Opening Series

2, Sike Unsafe java class of analytic magic

3, Sike java synchronized series of JMM (Java Memory Model)

4, Sike java synchronized series of volatile resolve

5, Sike java synchronized series of synchronized resolve

6, Sike java series of synchronous write himself a lock Lock

7, Sike java synchronized series of articles from the AQS

8, Sike ReentrantLock resolve java source code synchronized series of (a) - fair locks, lock unfair

9, Sike ReentrantLock resolve java source code synchronized series of (two) - Conditions Lock

10, Sike java synchronized series of ReentrantLock VS synchronized

11, Sike ReentrantReadWriteLock parse java source synchronous series

12, Sike Semaphore synchronization java source parsing Series

13, Sike java source parsing synchronous series CountDownLatch

14, Sike java synchronized series of AQS final chapter

15, Sike StampedLock parse java source synchronous series


I welcome the attention of the public number "Tong brother read source" view source code more series, and brother Tong source of ocean swim together.

qrcode

Guess you like

Origin www.cnblogs.com/tong-yuan/p/CyclicBarrier.html