CyclicBarrier源码解析

简介

从字面意思来理解Cyclic(循环的)Barrier(栅栏、屏障),主要的用途在于,让一组线程到达屏障时阻塞,直到最后一个线程也到达屏障时,线程才执行。默认的构造方法为CyclicBarrier(int parties),parties表示线程的数量,需要每个线程都调用await方法,通知已经到达屏障,进行线程阻塞。

应用场景

需要所有的子线程都完成时,才开始执行主线程。可以用于多线程计算数据,最后合并计算结果的应用场景,比如计算一个Excel中保存的所有订单的总金额,先通过多线程计算每个sheet中的订单总额,最后计算出所有订单的中金额。

与CountDownLatch的区别

CountDownLatch的计数器只能使用一次,而CyclicBarrier可以通过reset方法重置计数器,因此,CyclicBarrier能够处理更加复杂的业务场景,比如如果计算结果出错时,可以通过调用reset方法进行计数器重置,让线程重新进行计算。CyclicBarrier还提供了其他有用的方法,比如getNumberBarriers方法,可以获取当前阻塞的线程数量;isBroken方法,判断阻塞的线程是否中断。

主要的参数

    /** 
    * The lock for guarding barrier entry 
    * 控制屏障入口的锁
    */
    private final ReentrantLock lock = new ReentrantLock();
    /**
    *  Condition to wait on until tripped 
    *  等待直到被tipped的条件
    */
    private final Condition trip = lock.newCondition();
    /** 
    * The number of parties 
    * 记录线程数量
    */
    private final int parties;
    /* 
    * The command to run when tripped 
    * 该线程来源于高级构造方法CyclicBarrier(int parties, Runnable barrierAction)中进行初始化,
    * 用于记录当最后一个线程到达时,优先开始执行的线程
    */
    private final Runnable barrierCommand;
    /** 
    * The current generation 
    * 一个类部类,有一个变量broken用于判断阻塞的线程是否中断,默认false
    */
    private Generation generation = new Generation();

    /**
     * Number of parties still waiting. Counts down from parties to 0
     * on each generation.  It is reset to parties on each new
     * generation or when broken.
     * 这个是计录在等待线程的计数器,会做自减
     */
    private int count;

核心方法

主要的核心方法为await方法,代码如下:

public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }

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

测试案例

运行实例代码如下:

public class CyclicBarrierTest1 {

	static CyclicBarrier c = new CyclicBarrier(2);

	public static void main(String[] args) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					c.await();
				} catch (Exception e) {

				}
				System.out.println(1);
			}
		}).start();

		try {
			c.await();
		} catch (Exception e) {

		}
		System.out.println(2);
	}
}

输出
2
1
或者输出
1
2

如果把线程数new CyclicBarrier(2)改写成new CyclicBarrier(3),那么之前两个到达屏障的线程都不会执行,结果不会有输出,因为没有第三个线程到达屏障。

有一个高级构造方法CyclicBarrier(int parties, Runnable barrierAction),用于在最后一个线程到达屏障时,优先执行barrierAction线程,应用于复杂的业务场景。
代码如下:

public class CyclicBarrierTest2 {

	static CyclicBarrier c = new CyclicBarrier(2, new A());

	public static void main(String[] args) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					c.await();
				} catch (Exception e) {

				}
				System.out.println(1);
			}
		}).start();

		try {
			c.await();
		} catch (Exception e) {

		}
		System.out.println(2);
	}

	static class A implements Runnable {

		@Override
		public void run() {
			System.out.println(3);
		}

	}

}

输出
3
2
1

isBroken方法的用法如下:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest3 {

    static CyclicBarrier c = new CyclicBarrier(2);

    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    c.await();
                } catch (Exception e) {
                }
            }
        });
        thread.start();
        thread.interrupt();
        try {
            c.await();
        } catch (Exception e) {
            System.out.println(c.isBroken());
        }
    }
}

并发工具类(二)同步屏障CyclicBarrier
Java之CyclicBarrier使用

你可能感兴趣的:(Java)