CyclicBarrier 分析

簡介

  1. CyclicBarrier 是什麼?
  2. CyclicBarrier 使用
  3. CyclicBarrier 源碼解析
  4. CyclicBarrier 簡單實現
  5. barrierAction 是由哪個線程執行的?

CyclicBarrier 是什麼?

CyclicBarrier 開始於JDK 1.5, 一個同步工具類,允許一組線程都等待彼此到達公共屏障點。CyclicBarrier 在程序中非常有用,涉及到固定參數的線程數量等待彼此,這個 barrier 被稱爲 cyclic 是由於它可以所有的等待線程釋放之後,重複使用。
CyclicBarrier 支持一個可選的 Runnable 在每一個屏障點執行一次,在所有參與的線程到達之後,但是在執行之前所有的線程都釋放了, barrierAction非常有用的對於在任何參與者繼續之前更新共享狀態。

CyclicBarrier 使用

public class Test2 {

  static class A extends Thread {

    private CyclicBarrier cyclicBarrier;

    public A(CyclicBarrier cyclicBarrier, String name) {
      this.cyclicBarrier = cyclicBarrier;
      setName(name);
    }

    @Override
    public void run() {
      try {
        System.out.println(Thread.currentThread().getName() + " 準備完畢");
        cyclicBarrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (BrokenBarrierException e) {
        e.printStackTrace();
      }
    }
  }

  static class B extends Thread {

    private CyclicBarrier cyclicBarrier;

    public B(CyclicBarrier cyclicBarrier, String name) {
      this.cyclicBarrier = cyclicBarrier;
      setName(name);
    }

    @Override
    public void run() {
      try {
        System.out.println(Thread.currentThread().getName() + " 準備完畢");
        cyclicBarrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (BrokenBarrierException e) {
        e.printStackTrace();
      }
    }
  }

  static class C extends Thread {

    private CyclicBarrier cyclicBarrier;

    public C(CyclicBarrier cyclicBarrier, String name) {
      this.cyclicBarrier = cyclicBarrier;
      setName(name);
    }

    @Override
    public void run() {
      try {
        System.out.println(Thread.currentThread().getName() + " 準備完畢");
        cyclicBarrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (BrokenBarrierException e) {
        e.printStackTrace();
      }
    }
  }


  public static void main(String[] args) {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> System.out.println("完成"));
    new A(cyclicBarrier, "A").start();
    new B(cyclicBarrier, "B").start();
    new C(cyclicBarrier, "C").start();
  }
}
/**
output:

A 準備完畢
B 準備完畢
C 準備完畢
完成
*/

CyclicBarrier 源碼解析

在看源碼前,我們可以對源碼的實現進行一些猜想,根據 CyclicBarrier 前面的定義,可以猜想裏面有一個變量來表示參與者的數量,在使用調用 await 方法是時候,參與者的數量減一,直到參與者數量爲 0,存在 barrierAction,就執行barrierAction,由於可以重複使用,所以在barrierAction 執行對參與者的數量進行恢復。
下面看一下源碼實現是否於猜想的類似。

構造方法

parties 參與者的數量
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;
    }

await 方法

 public int await() throws InterruptedException, BrokenBarrierException {
        try {
            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();
            }
            // 減去一個參與者
            int index = --count;
           // 如果參與者數量爲0,判斷barrierAction是否爲null,不爲null, 將執行run方法,調用nextGeneration恢復狀態
            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();
        }
    }

nextGeneration 方法

private void nextGeneration() {
        // signal completion of last generation
        trip.signalAll();  // 喚醒參與者
        // set up next generation
        count = parties; // 恢復參與者的數量
        generation = new Generation(); // 下一代
    }

CyclicBarrier 簡單實現

藉助 AtomicInteger 來簡單實現

public class SimpleBarrier {

  private AtomicInteger count;
  int size;
  private Runnable command;

  public SimpleBarrier(int n) {
    this.count = new AtomicInteger(n);
    this.size = n;
  }

  public SimpleBarrier(int n, Runnable barrierAction) {
    this(n);
    this.command = barrierAction;
  }

  public void await() {
    int position = count.getAndDecrement();
    if (position == 1) {
      command.run();
      count.set(size);
    } else {
      while (count.get() != 0) {
      }
    }
  }
}
public class Test2 {

  static class A extends Thread {

    private SimpleBarrier cyclicBarrier;

    public A(SimpleBarrier cyclicBarrier, String name) {
      this.cyclicBarrier = cyclicBarrier;
      setName(name);
    }

    @Override
    public void run() {
      System.out.println(Thread.currentThread().getName() + " 準備完畢");
      cyclicBarrier.await();
    }
  }

  static class B extends Thread {

    private SimpleBarrier cyclicBarrier;

    public B(SimpleBarrier cyclicBarrier, String name) {
      this.cyclicBarrier = cyclicBarrier;
      setName(name);
    }

    @Override
    public void run() {
      System.out.println(Thread.currentThread().getName() + " 準備完畢");
      cyclicBarrier.await();
    }
  }

  static class C extends Thread {

    private SimpleBarrier cyclicBarrier;

    public C(SimpleBarrier cyclicBarrier, String name) {
      this.cyclicBarrier = cyclicBarrier;
      setName(name);
    }

    @Override
    public void run() {
      System.out.println(Thread.currentThread().getName() + " 準備完畢");
      cyclicBarrier.await();
    }
  }


  public static void main(String[] args) {
    SimpleBarrier cyclicBarrier = new SimpleBarrier(3, () -> System.out.println("完成"));
    new A(cyclicBarrier, "A").start();
    new B(cyclicBarrier, "B").start();
    new C(cyclicBarrier, "C").start();
  }
}
/**
output:
A 準備完畢
B 準備完畢
C 準備完畢
完成
*/

barrierAction 是由哪個線程執行的?

最後一個線程來執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章