1. 程式人生 > >併發程式設計-柵欄CyclicBarrier

併發程式設計-柵欄CyclicBarrier

柵欄類似於閉鎖,它能阻塞一組執行緒直到某個事件的發生,當參與的執行緒達到柵欄位置的時候,將會呼叫await()方法,這個將會阻塞當前執行緒直到所有的執行緒全部到達了柵欄。如果所有的執行緒都到達了柵欄,那麼柵欄便會開啟,此時所有的執行緒都會釋放,而柵欄將被重置以便下次使用。

CyclicBarrier有兩個構造器,可選的Runnable 表示的是執行緒通過柵欄的時候執行的程式碼。

其中parities表示的是參與執行緒的個數,當前執行緒在呼叫await()方法的時候會進行阻塞,呼叫await()方法,計數器+1.當計數器等於parities的時候,柵欄便會放開。也就是執行到最後一個參與執行緒,此執行緒呼叫await()方法的時候,所有執行緒同時執行。

CyclicBarrier(int parties) 
CyclicBarrier(int parties, Runnable barrierAction) 

依舊拿比賽的是事來說吧,這個CyclicBarrier,怎麼玩都可以的。比如下面這個例子是選手準備,然後釋放柵欄,run()方法程式碼執行完表示運動員到達終點。還有例子就是不管開始,只有所有人都完成比賽,可以慶祝之類的。無非是任務的類Runner類裡面的cyclicBarrier.await()位置的問題,選擇CyclicBarrier的第二個構造器即可。

public class Runner implements Runnable{
	private CyclicBarrier cyclicBarrier;
	private int number;
	
	public Runner(CyclicBarrier cyclicBarrier, int number) {
		this.cyclicBarrier = cyclicBarrier;
		this.number = number;
	}

	public void run() {
		try {
			System.out.println(number+"th 就位");
			cyclicBarrier.await();
			System.out.println(number+"th 到達,耗時"+Math.random()*1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}
	}
}
public class Race {
	public static void main(String[] args) {
		final int count = 6;
		CyclicBarrier cyclicBarrier = new CyclicBarrier(count);
		for(int i = 1 ; i <= count ;i++){
			new Thread(new Runner(cyclicBarrier,i)).start();
		}
	}
}
2th 就位
5th 就位
3th 就位
4th 就位
6th 就位
1th 就位
2th 到達,耗時896.3213862018172
3th 到達,耗時571.0326287073248
4th 到達,耗時625.9050513357512
6th 到達,耗時300.6048271390146
1th 到達,耗時706.7176368903195
5th 到達,耗時235.70225351556374

CyclicBarrier有Runnable引數的構造器CyclicBarrier(int parties, Runnable barrierAction),執行緒通過柵欄時,Runnable物件便會被呼叫。

例如:100米的比賽,所有參賽選手都到終點情況下,比賽結束,否則比賽還在進行中。    

public class Runner implements Runnable{

	private CyclicBarrier cyclicBarrier;
	private int number;
	
	public Runner(CyclicBarrier cyclicBarrier, int number) {
		this.cyclicBarrier = cyclicBarrier;
		this.number = number;
	}

	public void run() {
		try {
			System.out.println(number+"th 開跑!");
			Thread.sleep(1000);
			System.out.println(number+"th 到達!");
			cyclicBarrier.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}
	}
}
public class Race {
	public static void main(String[] args) {
		final int count = 6;
		CyclicBarrier cyclicBarrier = new CyclicBarrier(count,new Runnable(){
			public void run(){
				System.out.println("所有人到達終點,該比賽結束了");
			}
		});
		for(int i = 1 ; i <= count ;i++){
			new Thread(new Runner(cyclicBarrier,i)).start();
		}
	}
}
1th 起跑!
3th 起跑!
5th 起跑!
2th 起跑!
4th 起跑!
6th 起跑!
1th 到達!
5th 到達!
3th 到達!
6th 到達!
4th 到達!
2th 到達!
該比賽結束了
第二個例子將cyclicBarrier.await()方法放在Runner的最後,相當於是最後一個執行緒執行到這裡的時候,此時柵欄釋放。所有的 執行緒繼續執行。
    思想引入自《Java併發程式設計實戰》。