同時:CyclicBarrierの使用

3822 ワード

CyclicBarrier:共通バリアポイント(common barrier point)に達するまでスレッドのセットを互いに待つことができる同期支援クラス.一定サイズのスレッドのセットに関連するプログラムでは、これらのスレッドは常に互いに待たなければならない.この場合、CyclicBarrierは有用である.このbarrierは、待機スレッドを解放した後に再利用できるため、ループのbarrierと呼ばれる.
CyclicBarrierは、一連のスレッドの最後のスレッドが到着した後(ただし、すべてのスレッドを解放する前に)、各バリアポイントでのみ実行されるオプションのRunnableコマンドをサポートします.このバリア操作は、すべての参加スレッドを継続する前に共有状態を更新する場合に便利です.
1、使用構造方法:CyclicBarrier(int parties,Runnable barrier Action):指定された数の参加者(スレッド)が待機している間に起動し、barrierの起動時に、barrierに入る最後のスレッドによって実行される所与のバリア動作を実行する新しいCyclicBarrierを作成する.
注意:barrierActionは1回のみ実行されます
『Think In Java』の例を見てみましょう.
競馬ゲーム:(この例はよく見ると、よく書けています).

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

	@Override
	public void run() {
		try {
			while (!Thread.interrupted()) {
				synchronized (this) {
					strides += rand.nextInt(3);
				}
				barrier.await();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}
	}

	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 = 10;
	private List<Horse> horses = new ArrayList<Horse>();
	private ExecutorService exec = Executors.newCachedThreadPool();
	private CyclicBarrier barrier;

	public HorseRace(int nHorse, final int pause) {
		barrier = new CyclicBarrier(nHorse, new Runnable() {
			@Override
			public void run() {
				StringBuilder s = new StringBuilder();
				for(int i = 0; i < FINISH_LINE; i++){
					s.append("=");
				}
				System.out.println(s);
				for(Horse horse : horses){
					System.out.println(horse.tracks());
				}
				for(Horse horse : horses){
					if(horse.getStrides() >= FINISH_LINE){
						System.out.println(horse + " won!");
						exec.shutdown();
						return;
					}
					try {
						TimeUnit.MILLISECONDS.sleep(pause);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println("one time");
			}
		});
		for(int i = 0; i < nHorse; i++){
			Horse horse = new Horse(barrier);
			horses.add(horse);
			exec.execute(horse);
		}
	}
	public static void main(String[] args){
		int nHorses = 2;
		int pause = 5;
		new HorseRace(nHorses, pause);
	}
}

2、構築方法:CyclicBarrier(int parties):所定数の参加者(スレッド)が待機している間に開始する新しいCyclicBarrierを作成しますが、barrierの起動時に事前定義された操作を実行しません.
注意:この構成では,barrierのカウントが0の場合,他に統一的な動作はなく,各スレッドはそれぞれ残りのコードを実行する.たとえば、次のコードでは、5つのスレッドが互いに待機している場合、barrierのカウントが0の場合、helloが5回出力されます.

public void run() {
		try {
			barrier.await();
			System.out.println("hello");
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}