CyclicBarrier实现原理

引言

在写一个知识点之前,总是想说点废话。进程、线程之类的是操作系统级别上的概念,在此概念基础上使我们能够充分压榨CPU的处理能力,实现了并发和并行。但是呢,一涉及多线程的问题,总是有点不可控的感觉,对于线程的调度,很大程度上受操作系统调度算法的控制,而操作系统也开发了一些核心的api,可以让我们在用户的应用层面控制线程。

像CyclicBarrier就让我们在一定程度上,控制了多个线程的逻辑流,正常情况下,线程谁先执行,谁后执行是没法控制的。通过CyclicBarrier可以设置一个栅栏一样的东西,让多个线程都到达栅栏处才能继续往下执行。比如两个线程A、B,A执行的速度很快,很快到达了某一个点,但是此时B还慢悠悠的执行,此时线程A只能再栅栏处等待,直到线程B也到达栅栏处,才能继续往下执行。

下面直接从源码层面分析其实现原理。

实现原理

(1)实例化一个CyclicBarrier

提供了两个构造函数,parties表示有多少个个体(相当于调多少次await方法,每调一次await方法相当于一个线程到达了栅栏处),barrierAction其实相当于回调函数,当最后一个线程达到了栅栏处就会触发这个回调函数。

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

(2)核心方法await

// 这个方法不会超时,可以被中断
public int await() throws InterruptedException, BrokenBarrierException {
    try {
        return dowait(false, 0L);
    } catch (TimeoutException toe) {
        throw new Error(toe); // cannot happen
    }
}

// 这个方法有超时控制,如果在栅栏处等待时间过长,会自动返回触发超时异常
public int await(long timeout, TimeUnit unit)
    throws InterruptedException,
           BrokenBarrierException,
           TimeoutException {
    return dowait(true, unit.toNanos(timeout));
}

// 这个才是真正的核心方法
private int dowait(boolean timed, long nanos)
    throws InterruptedException, BrokenBarrierException,
           TimeoutException {
    final ReentrantLock lock = this.lock;
    // exclusive mode
    lock.lock();
    try {
        final Generation g = generation;
		
		// broken为true时,表示当前栅栏被打破,所有的线程都不会被阻塞了
        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语句,表示最后一个线程到达栅栏处了
                if (command != null)
                    command.run();
                ranAction = true;
                // 重新开始往栅栏冲刺
                nextGeneration();
                return 0;
            } finally {
                if (!ranAction)
                    breakBarrier();
            }
        }

        // loop until tripped, broken, interrupted, or timed out
        for (;;) {
            try {
            	// 如果不设置超时,调用await释放锁,同时阻塞
                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实现原理很简单,但是它却能控制多线程的行为,这是很值得称道的,而且这个类在
实际的开发中还是能够用到的。比如我们实现并行运算,一个线程算一部分数据,当算完之后,将多个结算汇总。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值