java.utils.concurrent 新類庫中的構件(二) CycliicBarrier

java.utils.concurrent 新類庫中的構件(二) CycliicBarrier

CycliicBarrier適用於這樣的情況:你希望創建一組任務,它們並行執行工作,然後再進行下一個步驟之前等待,直至所有的任務都完成(看起來有點像join())。它使得所有的並行任務都將在柵欄處列隊,因此可以一致的向前移動。這非常像CountDownLatch,只是CountDownLatch只是觸發一次的事件,而CycliicBarrier可以多次重用。
從剛開始接觸計算機開始,我就對仿真着迷,而併發是使仿真成爲可能的一個關鍵因素。我記得最開始編寫的一個程序就是一個仿真:一個通用BASIC編寫的賽馬遊戲。下面是那個程序的面向對象的多線程版本,其中使用了CycliicBarrier:

package concurrency;//: concurrency/HorseRace.java
// Using CyclicBarriers.
import java.util.concurrent.*;
import java.util.*;
import static net.mindview.util.Print.*;

class Horse implements Runnable {
  private static int counter = 0;
  private final int id = counter++;
  private int strides = 0;
  private static Random rand = new Random(47);
  private static CyclicBarrier barrier;
  public Horse(CyclicBarrier b) { barrier = b; }
  public synchronized int getStrides() { return strides; }
  public void run() {
    try {
      while(!Thread.interrupted()) {
        synchronized(this) {
          strides += rand.nextInt(3); // Produces 0, 1 or 2
        }
        barrier.await();
      }
    } catch(InterruptedException e) {
      // A legitimate way to exit
    } catch(BrokenBarrierException e) {
      // This one we want to know about
      throw new RuntimeException(e);
    }
  }
  public String toString() { return "Horse " + id + " "; }
  public String tracks() {
    StringBuilder s = new StringBuilder();
    for(int i = 0; i < getStrides(); i++)
      s.append("*");
    s.append(id);
    return s.toString();
  }
}

public class HorseRace {
  static final int FINISH_LINE = 75;
  private List<Horse> horses = new ArrayList<Horse>();
  private ExecutorService exec =
    Executors.newCachedThreadPool();
  private CyclicBarrier barrier;
  public HorseRace(int nHorses, final int pause) {
    barrier = new CyclicBarrier(nHorses, new Runnable() {
      public void run() {
        StringBuilder s = new StringBuilder();
        for(int i = 0; i < FINISH_LINE; i++)
          s.append("="); // The fence on the racetrack
        print(s);
        for(Horse horse : horses)
          print(horse.tracks());
        for(Horse horse : horses)
          if(horse.getStrides() >= FINISH_LINE) {
            print(horse + "won!");
            exec.shutdownNow();
            return;
          }
        try {
          TimeUnit.MILLISECONDS.sleep(pause);
        } catch(InterruptedException e) {
          print("barrier-action sleep interrupted");
        }
      }
    });
    for(int i = 0; i < nHorses; i++) {
      Horse horse = new Horse(barrier);
      horses.add(horse);
      exec.execute(horse);
    }
  }
  public static void main(String[] args) {
    int nHorses = 7;
    int pause = 200;
    if(args.length > 0) { // Optional argument
      int n = new Integer(args[0]);
      nHorses = n > 0 ? n : nHorses;
    }
    if(args.length > 1) { // Optional argument
      int p = new Integer(args[1]);
      pause = p > -1 ? p : pause;
    }
    new HorseRace(nHorses, pause);
  }
} /* (Execute to see output) *///:~

可以向CyclicBarrier提供一個“柵欄動作”,它是一個Runnable,當計數值到達0時自動執行行–這是CycliBarrier和countDownLatch的另一個區別。這裏,柵欄動作是作爲你明內部類創建的,它被提交給了CyclicBarrier的構造器。
我試圖讓每匹馬都打印自己,但是之後的顯示順序取決於任務管理器。CyclicBarrier使得每匹馬都要執行爲了向前移動所必須執行的所有工作,然後必須在柵欄處等待其他所有的馬都準備完畢。當所有的馬都向前移動時, CyclicBarrier將自動調用Runnable柵欄動作任務,按順序顯示馬和終點線的位置。
一旦所有的任務都越過柵欄,它就會自動地爲下一回合比賽做好準備。

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