java.util.Concurrent.CyclicBarrier 源码

类图

源码

package java.util.concurrent;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;


public class CyclicBarrier {
    //使用ReentrantLock可重入独占锁
    private final ReentrantLock lock = new ReentrantLock();
    //创建一个条件队列
    private final Condition trip = lock.newCondition();
    //通过构造器传入的参数.表示总的等待线程的数量
    private final int parties;
    //当屏障正常打开后运行的程序,通过最后一个调用await的线程来执行
    private final Runnable barrierCommand;
    //当前的Generation。每当屏障失效或者开闸之后都会自动替换掉。从而实现重置的功能
    private Generation generation = new Generation();
    //实际仍在等待的线程数.当有一个线程到达屏障点,count值就会减一;当一次新的运算开始后,count的值被重置为parties
    private int count;

    //内部类
    private static class Generation {
        boolean broken = false;//表示当前的屏障是否被打破
    }

    //创建一个CyclicBarrier实例,parties指定参与相互等待的线程数
    public CyclicBarrier(int parties) {
        this(parties, null);
    }

    //创建一个CyclicBarrier实例,parties指定参与相互等待的线程数
    //barrierAction指定当所有线程到达屏障点之后,首先执行的操作,该操作由最后一个进入屏障点的线程执行。
    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

    //返回参与相互等待的线程数
    public int getParties() {
        return parties;
    }

    //该方法被调用时表示当前线程已经到达屏障点,当前线程阻塞进入休眠状态
    //直到所有线程都到达屏障点,当前线程才会被唤醒
    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe);
        }
    }

    //该方法被调用时表示当前线程已经到达屏障点,当前线程阻塞进入休眠状态
    //在timeout指定的超时时间内,等待其他参与线程到达屏障点
    //如果超出指定的等待时间,则抛出TimeoutException异常,如果该时间小于等于零,则此方法根本不会等待
    public int await(long timeout, TimeUnit unit) throws  InterruptedException,BrokenBarrierException,TimeoutException {
        return dowait(true, unit.toNanos(timeout));
    }

    //该方法被调用时表示当前线程已经到达屏障点,当前线程阻塞进入休眠状态
    //在timeout指定的超时时间内,等待其他参与线程到达屏障点
    //如果超出指定的等待时间,则抛出TimeoutException异常,如果该时间小于等于零,则此方法根本不会等待
    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)//如果当前Generation是处于打破状态则传播这个BrokenBarrierExcption
                throw new BrokenBarrierException();

            if (Thread.interrupted()) {
                breakBarrier();//如果当前线程被中断则使得当前generation处于打破状态,重置剩余count,并且唤醒状态变量.这时候其他线程会传播BrokenBarrierException
                throw new InterruptedException();
            }

            int index = --count;//尝试降低当前count
            if (index == 0) {
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    //当所有参与的线程都到达屏障点,立即去唤醒所有处于休眠状态的线程,恢复执行
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)//如果运行command失败也会导致当前屏障被打破
                        breakBarrier();
                }
            }


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

    //唤醒所有处于休眠状态的线程,恢复执行
    //重置count值为parties
    //重置中断状态为false
    private void nextGeneration() {
        trip.signalAll();
        count = parties;
        generation = new Generation();
    }

    //唤醒所有处于休眠状态的线程,恢复执行
    //重置count值为parties
    //重置中断状态为true
    private void breakBarrier() {
        generation.broken = true;
        count = parties;
        trip.signalAll();
    }

    //判断此屏障是否处于中断状态。
    //如果因为构造或最后一次重置而导致中断或超时,从而使一个或多个参与者摆脱此屏障点,或因为异常而导致某个屏障操作失败,则返回true;否则返回false
    public boolean isBroken() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return generation.broken;
        } finally {
            lock.unlock();
        }
    }

    //将屏障重置为其初始状态
    public void reset() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //唤醒所有等待的线程继续执行,并设置屏障中断状态为true
            breakBarrier();
            //唤醒所有等待的线程继续执行,并设置屏障中断状态为false
            nextGeneration();
        } finally {
            lock.unlock();
        }
    }

    //返回当前在屏障处等待的参与者数目,此方法主要用于调试和断言
    public int getNumberWaiting() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return parties - count;
        } finally {
            lock.unlock();
        }
    }
}

类 CyclicBarrier

    extends Object

    一个同步辅助类:它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。

    在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。

    因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

    CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

 

构造方法摘要

CyclicBarrier(int parties) 
          创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。
CyclicBarrier(int parties, Runnable barrierAction) 
          创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。

方法摘要

 int await() 
          在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
 int await(long timeout, TimeUnit unit) 
          在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。
 int getNumberWaiting() 
          返回当前在屏障处等待的参与者数目。
 int getParties() 
          返回要求启动此 barrier 的参与者数目。
 boolean isBroken() 
          查询此屏障是否处于损坏状态。
 void reset() 
          将屏障重置为其初始状态。

CyclicBarrier:将使count等于parties

public CyclicBarrier(int parties,Runnable barrierAction)

    创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。

    参数:

    parties - 在启动 barrier 前必须调用 await() 的线程数

    barrierAction - 在启动 barrier 时执行的命令;如果不执行任何操作,则该参数为 null

    抛出:

    IllegalArgumentException - 如果 parties 小于 1

CyclicBarrier:将使count等于parties

public CyclicBarrier(int parties)

    创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。

    参数:

    parties - 在启动 barrier 前必须调用 await() 的线程数

    抛出:

    IllegalArgumentException - 如果 parties 小于 1

getParties:得到parties的值

public int getParties()

    返回要求启动此 barrier 的参与者数目。

    返回:

        要求启动此 barrier 的参与者数目

await:count减1,若count等于0,则唤醒等待的线程;不等于0,则挂起等待

public int await() throws InterruptedException, BrokenBarrierException

    在所有 参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。

    如果当前线程不是将到达的最后一个线程,出于调度目的,将禁用它,且在发生以下情况之一前,该线程将一直处于休眠状态:

  • 最后一个线程到达;或者
  • 其他某个线程中断当前线程;或者
  • 其他某个线程中断另一个等待线程;或者
  • 其他某个线程在等待 barrier 时超时;或者
  • 其他某个线程在此 barrier 上调用 reset()

    如果当前线程:

  • 在进入此方法时已经设置了该线程的中断状态;或者
  • 在等待时被中断

    则抛出 InterruptedException,并且清除当前线程的已中断状态。

    如果在线程处于等待状态时 barrier 被 reset(),或者在调用 await 时 barrier 被损坏,抑或任意一个线程正处于等待状态,则抛出 BrokenBarrierException 异常。

    如果任何线程在等待时被 中断,则其他所有等待线程都将抛出 BrokenBarrierException 异常,并将 barrier 置于损坏状态。

    如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作,则在允许其他线程继续运行之前,当前线程将运行该操作。如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。

    返回:

        到达的当前线程的索引,其中,索引 getParties() - 1 指示将到达的第一个线程,零指示最后一个到达的线程

    抛出:

    InterruptedException - 如果当前线程在等待时被中断

    BrokenBarrierException - 如果 另一个 线程在当前线程等待时被中断或超时,或者重置了 barrier,或者在调用 await 时 barrier 被损坏,抑或由于异常而导致屏障操作(如果存在)失败。

await:count减1,若count等于0,则唤醒等待的线程;不等于0,则挂起等待指定时间。在过了指定时间之后,count仍不等于0,则抛出异常。

public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException

    在所有 参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。

    如果当前线程不是将到达的最后一个线程,出于调度目的,将禁用它,且在发生以下情况之一前,该线程将一直处于休眠状态:

  • 最后一个线程到达;
  • 超出指定的超时时间;
  • 其他某个线程中断当前线程;
  • 其他某个线程中断另一个等待线程;
  • 其他某个线程在等待 barrier 时超时;
  • 其他某个线程在此 barrier 上调用 reset()

    如果当前线程,在以下情况中的一种时:

  • 在进入此方法时已经设置了该线程的中断状态;
  • 在等待时被中断

    则抛出 InterruptedException,并且清除当前线程的已中断状态。

    如果超出指定的等待时间,则抛出 TimeoutException 异常。如果该时间小于等于零,则此方法根本不会等待。

    如果在线程处于等待状态时 barrier 被 reset(),或者在调用 await 时 barrier 被损坏,抑或任意一个线程正处于等待状态,则抛出 BrokenBarrierException 异常。

    如果任何线程在等待时被中断,则其他所有等待线程都将抛出 BrokenBarrierException,并将屏障置于损坏状态。

    如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作,则在允许其他线程继续运行之前,当前线程将运行该操作。如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。

    参数:

    timeout - 等待 barrier 的时间

    unit - 超时参数的时间单位

    返回:

        到达的当前线程的索引,其中,索引 getParties() - 1 指示第一个将要到达的线程,零指示最后一个到达的线程

    抛出:

    InterruptedException - 如果当前线程在等待时被中断

    TimeoutException - 如果超出了指定的超时时间

    BrokenBarrierException - 如果 另一个 线程在当前线程等待时被中断或超时,或者重置了 barrier,或者调用 await 时 barrier 被损坏,抑或由于异常而导致屏障操作(如果存在)失败。

isBroken:判断屏障是否损坏

public boolean isBroken()

    查询此屏障是否处于损坏状态。

    返回:

        如果多次调用构造函数或者使用重置函数reset(),在屏障等待的参与者的等待状态会被中断或超时,从而抛出异常。因为异常而导致某个屏障操作失败,则返回 true;否则返回 false

reset:屏障状态重置为true,count等于parties。

public void reset()

    将屏障重置为其初始状态。如果所有参与者目前都在屏障处等待,则它们将返回,同时抛出一个 BrokenBarrierException

    注意:在由于其他原因造成损坏(broken)之后,实行重置可能会变得很复杂;此时需要使用其他方式重新同步线程,并选择其中一个线程来执行重置。与为后续使用创建一个新 barrier 相比,这种方法可能更好一些。

getNumberWaiting:得到当前在屏障处等待的参与数

public int getNumberWaiting()

    返回当前在屏障处等待的参与者数目。此方法主要用于调试和断言。

    返回:

        当前阻塞在 await() 中的参与者数目。

使用实例:

  • 1.新建5个线程,这5个线程达到一定的条件时,它们才继续往后运行。
package com.thread;

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

public class CyclicBarrierTest1 extends Thread {
    private static int SIZE = 5;
    private static CyclicBarrier cb;

    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + " wait for CyclicBarrier.");
            // CyclicBarrier的count减1,若count等于0,则唤醒在屏障处等待的所有线程
            cb.await();
            System.out.println(Thread.currentThread().getName() + " continued.");
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        cb = new CyclicBarrier(SIZE);
        // 新建5个任务
        for (int i = 0; i < SIZE; i++)
            new CyclicBarrierTest1().start();
    }
}

    运行结果:

Thread-1 wait for CyclicBarrier.
Thread-3 wait for CyclicBarrier.
Thread-0 wait for CyclicBarrier.
Thread-2 wait for CyclicBarrier.
Thread-4 wait for CyclicBarrier.
Thread-4 continued.
Thread-3 continued.
Thread-2 continued.
Thread-1 continued.
Thread-0 continued.

  • 2.新建5个线程,当这5个线程达到一定的条件时,执行某项任务。
package com.thread;

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

public class CyclicBarrierTest2 extends Thread {
    private static int SIZE = 5;
    private static CyclicBarrier cb;

    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + " wait for CyclicBarrier.");
            // CyclicBarrier的count减1,若count等于0,则唤醒在屏障处等待的所有线程
            cb.await();
            System.out.println(Thread.currentThread().getName() + " continued.");
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        cb = new CyclicBarrier(SIZE, new Runnable() {
            public void run() {//当其他的线程都已达到barrier,先执行当前任务,再让其他线程继续执行
                System.out.println("CyclicBarrier's parties is: " + cb.getParties());
            }
        });
        // 新建5个任务
        for (int i = 0; i < SIZE; i++)
            new CyclicBarrierTest1().start();
    }
}

    运行结果:

Thread-0 wait for CyclicBarrier.
Thread-2 wait for CyclicBarrier.
Thread-1 wait for CyclicBarrier.
Thread-4 wait for CyclicBarrier.
Thread-3 wait for CyclicBarrier.
CyclicBarrier's parties is: 5
Thread-3 continued.
Thread-1 continued.
Thread-4 continued.
Thread-0 continued.
Thread-2 continued.

猜你喜欢

转载自my.oschina.net/u/3858564/blog/2881761
今日推荐