現實生活中我們經常會遇到這樣的情景,在進行某個活動前需要等待人全部都齊了才開始。例如吃飯時要等全家人都上座了才動筷子,旅遊時要等全部人都到齊了才出發,比賽時要等運動員都上場後才開始。
柵欄類似於閉鎖,它能阻塞一組執行緒直到某個事件的發生。柵欄與閉鎖的關鍵區別在於,所有的執行緒必須同時到達柵字段置,才能繼續執行。閉鎖用於等待事件,而柵欄用於等待其他執行緒。
cyclicbarrier可以使一定數量的執行緒反覆地在柵字段置處匯集。當執行緒到達柵字段置時將呼叫await方法,這個方法將阻塞直到所有執行緒都到達柵字段置。如果所有執行緒都到達柵字段置,那麼柵欄將開啟,此時所有的執行緒都將被釋放,而柵欄將被重置以便下次使用。
cyclicbarrier類圖:
cyclicbarrier是由reentrantlock可重入鎖和condition共同實現的。
cyclicbarrier有兩個構造方法
public cyclicbarrier(int parties)
public cyclicbarrier(int parties, runnable barrieraction)
cyclicbarrier預設的構造方法是cyclicbarrier(int parties),其引數表示屏障攔截的執行緒數量,每個執行緒使用await()方法告訴cyclicbarrier我已經到達了屏障,然後當前執行緒被阻塞。
cyclicbarrier的另乙個建構函式cyclicbarrier(int parties, runnable barrieraction),用於執行緒到達屏障時,優先執行barrieraction,方便處理更複雜的業務場景。
public int await() throws interruptedexception, brokenbarrierexception catch (timeoutexception toe)
}public int await(long timeout, timeunit unit)
throws interruptedexception,
brokenbarrierexception,
timeoutexception
這兩個方法最終都會呼叫dowait(boolean, long)方法,它也是cyclicbarrier的核心方法,該方法定義如下:
private int dowait(boolean timed, long nanos)
throws interruptedexception, brokenbarrierexception,
timeoutexception
// 獲取下標
int index = --count;
// 如果是 0,說明最後乙個執行緒呼叫了該方法
if (index == 0) finally
}for (;;) catch (interruptedexception ie) else
}if (g.broken)
throw new brokenbarrierexception();
if (g != generation)
return index;
if (timed && nanos <= 0l)
}} finally
}
dowait(boolean, long)方法的主要邏輯處理比較簡單,如果該執行緒不是最後乙個呼叫await方法的執行緒,則它會一直處於等待狀態,除非發生以下情況:
在上面的源**中,我們可能需要注意generation 物件,在上述**中我們總是可以看到丟擲brokenbarrierexception異常,那麼什麼時候丟擲異常呢?如果乙個執行緒處於等待狀態時,如果其他執行緒呼叫reset(),或者呼叫的barrier原本就是被損壞的,則丟擲brokenbarrierexception異常。同時,任何執行緒在等待時被中斷了,則其他所有執行緒都將丟擲brokenbarrierexception異常,並將barrier置於損壞狀態。
同時,generation描述著cyclicbarrier的更新換代。在cyclicbarrier中,同一批執行緒屬於同一代。當有parties個執行緒到達barrier之後,generation就會被更新換代。其中broken標識該當前cyclicbarrier是否已經處於中斷狀態。
private static class generation
預設barrier是沒有損壞的。當barrier損壞了或者有乙個執行緒中斷了,則通過breakbarrier()來終止所有的執行緒:
private void breakbarrier()
在breakbarrier()中除了將broken設定為true,還會呼叫signalall將在cyclicbarrier處於等待狀態的執行緒全部喚醒。
當所有執行緒都已經到達barrier處(index == 0),則會通過nextgeneration()進行更新換地操作,在這個步驟中,做了三件事:喚醒所有執行緒,重置count,generation:
private void nextgeneration()
示例,召喚7個神龍士找龍珠,先找齊7個神龍士,先到的等後到的,然後神龍士去找龍珠,找到了說一聲,等待其他人找到並召喚神龍
Const 深度解析
物件導向是c 的重要特性.但是c 在c的基礎上新增加的幾點優化也是很耀眼的 就const直接可以取代c中的 define 以下幾點很重要,學不好後果也也很嚴重 1.const常量,如const int max 100 優點 const常量有資料型別,而巨集常量沒有資料型別。編譯器可以對前者進行型別安...
extern深度解析
c語言中extern用法 對於全域性變數來說,extern關鍵字可以在乙個模組中使用在另乙個模組中定義的全域性變數.只要extern宣告一下就好,但是變數只能定義一次,不然鏈結的時候會報錯.現代 編譯器一般採用按檔案編譯的方式,因此在編譯時,各個檔案中定義的 全域性變數 是互相不透明的。也就是說,在...
cin深度解析
cin cin.get,cin.getline等函式深入分析 很多初學者都認為cin函式是乙個很簡單的函式,其實不然!cin函式有很多需要了解的知識 比如 cin的返回值是什麼,cin提供了哪些成員函式且分別是什麼作用,如cin.clear cin.ignore cin.fail cin.good ...