CyclicBarrier源码分析

Posted 醉酒的小男人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CyclicBarrier源码分析相关的知识,希望对你有一定的参考价值。

简单介绍

Cyclibarrier内部持有Lock和Condition对象,定义一个资源的值,然后开启与资源值相同数量的线程,在线程运行期间,调用await()方法暂停执行,当所有线程都调用完await()方法,资源数量将达到0,最后一次调用await()的线程,在Cyclibarrier内部,会执行signalAll()唤醒所有等待线程。说的意思就是让一组线程等待直到一个屏障条件到达才接着执行后续代码。也叫循环栅栏,和CountDownLatch差不多,但是有区别。

源码解析

package com;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    static class MyThread extends Thread {
        private CyclicBarrier cyclicBarrier;

        public MyThread(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            System.out.println("线程" + Thread.currentThread().getName() + "正在准备...");
            try {
                Thread.sleep(5000)
                System.out.println("线程" + Thread.currentThread().getName() + "准备完毕");
                cyclicBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "所有线程准备完毕,各自继续处理其他任务...");
        }
    }

    public static void main(String[] args) {
        int cnt = 4;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(cnt);
        for (int i = 0; i < cnt; i++) {
            new MyThread(cyclicBarrier).start();
        }
    }
}

执行结果:

从上面可以看出,每一个线程都必须等到所有线程准备完毕之后才能各自执行其后续操作,这个条件就是屏障状态barrier,当调用cyclicBarrier.await()方法之后,线程处于等待barrier状态而无法执行后续的程序代码。

CyclicBarrier构造方法

 public CyclicBarrier(int parties) {
        this(parties, null);
 }
    
public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
}    

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

以上是关于CyclicBarrier源码分析的主要内容,如果未能解决你的问题,请参考以下文章

JDK源码分析通过源码分析CyclicBarrier

多线程等待所有子线程执行完使用总结——CyclicBarrier使用和源码初步分析

源码分析-CyclicBarrier

Java并发包中CyclicBarrier的源码分析和使用

深入浅出Java并发编程指南「源码原理系列」让我们一起探索一下CyclicBarrier的技术原理和源码分析

JAVA并发包源码分析循环栅栏:CyclicBarrier