barrier(屏障)與互斥量,讀寫鎖,自旋鎖不一樣,它不是用來保護臨界區的。相反,它跟條件變量同樣,是用來協同多線程一塊兒工做的。
條件變量是多線程間傳遞狀態的改變來達到協同工做的效果。屏障是多線程各自作本身的工做,若是某一線程完成了工做,就等待在屏障那裏,直到其餘線程的工做都完成了,再一塊兒作別的事。舉個通俗的例子:
1.對於條件變量。在接力賽跑裏,1號隊員開始跑的時候,2,3,4號隊員都站着不動,直到1號隊員跑完一圈,把接力棒給2號隊員,2號隊員收到接力棒後就能夠跑了,跑完再給3號隊員。這裏這個接力棒就至關於條件變量,條件知足後就能夠由下一個隊員(線程)跑。
2.對於屏障:在百米賽跑裏,比賽沒開始以前,每一個運動員都在賽場上自由活動,有的熱身,有的喝水,有的跟教練談論。比賽快開始時,準備完畢的運動員就預備在起跑線上,若是有個運動員還沒準備完(除去特殊狀況),他們就一直等,直到運動員都在起跑線上,裁判喊口號後再開始跑。這裏的起跑線就是屏障,作完準備工做的運動員都等在起跑線,直到其餘運動員也把準備工做作完。javascript
java.util.concurrent.CyclicBarrier類是一個同步機制。它能夠經過一些算法來同步線程處理的過程。換言之,就是全部的線程必須等待對方,直到全部的線程到達屏障,而後繼續運行。下面這個圖能夠說明:
java
兩個線程經過調用CyclicBarrier的 await() 相互等待對方,一旦全部的線程都在CyclicBarrier中等待,而後全部的線程一塊兒釋放而後繼續執行。算法
當你要建立CyclicBarrier的時候必須指定在釋放他們前有多少個線程等待,下面是一個例子:編程
CyclicBarrier barrier = new CyclicBarrier(2);複製代碼
下面是在CyclicBarrier處等待:多線程
barrier.await();複製代碼
你也能夠指線程等待的超時時間,當等待超時的時候,線程依然會被釋放。即便並非全部的線程都開始在CyclicBarrier等待。下面這行代碼指定超時時間:併發
barrier.await(10, TimeUnit.SECONDS);複製代碼
全部線程在CyclicBarrier等待,是指:
• 最後一個線程到達(調用await方法)this
• 一個線程被被另一個線程中斷(另一個線程調用了這個現場的interrupt()方法)spa
• 其中一個等待的線程被中斷線程
• 其中一個等待的線程超時code
• 一個外部的線程調用了yclicBarrier.reset()方法。
CyclicBarrier 支持一個Runnable屏障動做。當最後一個線程到達的時候,這個Runable對象就能夠被執行。你須要將這個Runable屏障動做放置在他的構造器中,就像這樣:
Runnable barrierAction = ... ;
CyclicBarrier barrier = new CyclicBarrier(2, barrierAction);複製代碼
下面這個例子說明了如何使用CyclicBarrier:
Runnable barrier1Action = new Runnable() {
public void run() {
System.out.println("BarrierAction 1 executed ");
}
};
Runnable barrier2Action = new Runnable() {
public void run() {
System.out.println("BarrierAction 2 executed ");
}
};
CyclicBarrier barrier1 = new CyclicBarrier(2, barrier1Action);
CyclicBarrier barrier2 = new CyclicBarrier(2, barrier2Action);
CyclicBarrierRunnable barrierRunnable1 =
new CyclicBarrierRunnable(barrier1, barrier2);
CyclicBarrierRunnable barrierRunnable2 =
new CyclicBarrierRunnable(barrier1, barrier2);
new Thread(barrierRunnable1).start();
new Thread(barrierRunnable2).start();
Here is the CyclicBarrierRunnable class:複製代碼
下面是CyclicBarrierRunnable類:
public class CyclicBarrierRunnable implements Runnable{
CyclicBarrier barrier1 = null;
CyclicBarrier barrier2 = null;
public CyclicBarrierRunnable(
CyclicBarrier barrier1,
CyclicBarrier barrier2) {
this.barrier1 = barrier1;
this.barrier2 = barrier2;
}
public void run() {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() +
" waiting at barrier 1");
this.barrier1.await();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() +
" waiting at barrier 2");
this.barrier2.await();
System.out.println(Thread.currentThread().getName() +
" done!");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}複製代碼
下面是控制檯的輸出。可是要注意有時候輸出的順序會發生變化,有時候是Thread-0先打印,有時候是Thread-1先打印。
Thread-0 waiting at barrier 1
Thread-1 waiting at barrier 1
BarrierAction 1 executed
Thread-1 waiting at barrier 2
Thread-0 waiting at barrier 2
BarrierAction 2 executed
Thread-0 done!
Thread-1 done!複製代碼
新書《Java併發編程系統與模型》目前已經寫完一部分。可是實際上說實話,並不知道讀者們對java併發系統有哪些比較關心的,並且閉門造車實在是太累,寫出來怕沒人看。因此我放在這裏徵求你們的意見。你們能夠直接在評論裏提問或者但願做者重點描寫哪一部份內容,我好有針對性的寫。