countdownlatch中count down是倒數的意思,latch則是門閂的含義。整體含義可以理解為倒數的門栓,似乎有一點「三二一,芝麻開門」的感覺。countdownlatch的作用也是如此,在構造countdownlatch的時候需要傳入乙個整數n,在這個整數「倒數」到0之前,主線程需要等待在門口,而這個「倒數」過程則是由各個執行執行緒驅動的,每個執行緒執行完乙個任務「倒數」一次。總結來說,countdownlatch的作用就是等待其他的執行緒都執行完任務,必要時可以對各個任務的執行結果進行彙總,然後主線程才繼續往下執行。
countdownlatch主要有兩個方法:countdown()和await()。countdown()方法用於使計數器減一,其一般是執行任務的執行緒呼叫,await()方法則使呼叫該方法的執行緒處於等待狀態,其一般是主線程呼叫。這裡需要注意的是,countdown()方法並沒有規定乙個執行緒只能呼叫一次,當同乙個執行緒呼叫多次countdown()方法時,每次都會使計數器減一;另外,await()方法也並沒有規定只能有乙個執行緒執行該方法,如果多個執行緒同時執行await()方法,那麼這幾個執行緒都將處於等待狀態,並且以共享模式享有同乙個鎖
public
static
void
main
(string[
] args)
catch
(interruptedexception e)}}
; thread thread2 =
newthread()
catch
(interruptedexception e)}}
; thread1.
start()
; thread2.
start()
;}
列印結果:
釋放latchcountdownlatch的資料結構do other thing
從原始碼可知,其底層是由aqs提供支援,所以其資料結構可以參考aqs的資料結構,而aqs的資料結構核心就是兩個虛擬佇列:同步佇列sync queue 和條件佇列condition queue,不同的條件會有不同的條件佇列。它可以用來實現可以依賴 int 狀態的同步器,獲取和釋放引數以及乙個內部fifo等待佇列深入理解aqs原理
countdownlatch原始碼
countdownlatch
(int count)
構造乙個用給定計數初始化的 countdownlatch。
// 使當前執行緒在鎖存器倒計數至零之前一直等待,除非執行緒被中斷。
void
await()
// 使當前執行緒在鎖存器倒計數至零之前一直等待,除非執行緒被中斷或超出了指定的等待時間。
boolean
await
(long timeout, timeunit unit)
// 遞減鎖存器的計數,如果計數到達零,則釋放所有等待的執行緒。
void
countdown()
// 返回當前計數。
long
getcount()
// 返回標識此鎖存器及其狀態的字串。
string tostring
()
建構函式:
//count小於0,則丟擲異常
public
countdownlatch
(int count)
內部類sync,sync繼承於aqs類
private
static
final
class
sync
extends
abstractqueuedsynchronizer
//在aqs中,state是乙個private volatile long型別的物件。
//對於countdownlatch而言,state表示的」鎖計數器「。
//countdownlatch中的getcount()
//最終是呼叫aqs中的getstate(),返回的state物件,即」鎖計數器「。
intgetcount()
//嘗試獲取共享鎖
protected
inttryacquireshared
(int acquires)
//嘗試釋放共享鎖
protected
boolean
tryreleaseshared
(int releases)
}}
//countdownlatch持有aqs鎖的成員變數
private
final sync sync;
await()方法
呼叫 await() 方法時,先去獲取 state 的值,當計數器不為0的時候,說明還有需要等待的執行緒在執行,則呼叫 doacquiresharedinterruptibly 方法,進來執行的第乙個動作就是嘗試加入等待佇列 ,即呼叫 addwaiter()方法
public
void
await()
throws interruptedexception
//aqs中方法
public
final
void
acquiresharedinterruptibly
(int arg)
throws interruptedexception
//sync中嘗試獲取共享鎖
protected
inttryacquireshared
(int acquires)
假設此時共享鎖獲取失敗,則開始呼叫doacquiresharedinterruptibly()方法
將當前執行緒加入等待佇列,並通過 parkandcheckinterrupt()方法實現當前執行緒的阻塞
//aqs中模板方法
private
void
doacquiresharedinterruptibly
(int arg)
throws interruptedexception
}//判斷當前節點是否需要阻塞,如果當前節點的前繼節點不是head,則需要if(
shouldparkafte***iledacquire
(p, node)
&&//阻塞執行緒
parkandcheckinterrupt()
)throw
newinterruptedexception()
;}}finally
}//喚醒節點
private
void
setheadandpropagate
(node node,
int propagate)
}//釋放執行緒,實際就是設定waitstatus為0
private
void
doreleaseshared()
else
if(ws ==0&&
!compareandsetwaitstatus
(h,0
, node.propagate)
)continue
;// loop on failed cas
}//在迴圈過程中,為了防止在上述操作中新增了新節點的情況
//通過檢測頭節點是否改變,如果改變了就繼續迴圈
if(h == head)
// loop if head changed
break;}
}//解除阻塞
private
void
unparksuccessor
(node node)
//呼叫unsafe類的unpark,解除阻塞
//這是cpu級別的操作
if(s != null)
locksupport.
unpark
(s.thread)
;}
呼叫await()方法的執行緒想要獲取鎖,有兩個條件:
countdonw()釋放鎖
當計數器為 0 後,會喚醒等待佇列裡的所有執行緒,所有呼叫了 await() 方法的執行緒都被喚醒,併發執行
public
void
countdown()
//sync中方法
public
final
boolean
releaseshared
(int arg)
return
false;}
//sync中方法
protected
boolean
tryreleaseshared
(int releases)
}
使用countdown,每次使用計數器值-1,當計數器值為0,釋放執行緒。
總結
深入鎖和併發的核心 併發工具類(3)
這三個類都是在定義在jdk的並發包util.concurrent中的併發工具類,用來實現多種不同用途的同步元件。我更願意將其稱為柵欄,有了circle是說明這個工具是可以迴圈使用的。當乙個業務的情景適用於要等到多個執行緒同時準備好後,比如各個分銀行的業務處理完成後,總銀行才能進行結賬這樣的場景。就可...
C語言的入門和深入
您可以使用渲染latex數學表示式 katex gamma公式展示 n n 1 n n gamma n n 1 quad forall n in mathbb n n n 1 n n 是通過尤拉積分 z 0 tz 1e t dt gamma z int 0 infty t e dt z 0 t z ...
深入玩轉K8S之簡單的業務彈性伸縮和滾動更新操作
首先是彈性伸縮,很簡單就是通過編寫deployment檔案,把副本數增大,就完成了業務的彈性擴充套件,那麼擴充套件完了怎麼調小呢,那麼也按照剛才的方法進行調整副本大小即可。最後說下滾動更新的操作,也很簡單跟剛才彈性伸縮差不多,為了方便區分,這裡弄了多個deployment,按照v1,v2來區分。ok...