LockSupport(park/unpark)源碼分析

關於LockSupport

concurrent包的基礎

Doug Lea 的神作concurrent包是基於AQS (AbstractQueuedSynchronizer)框架,AQS框架藉助於兩個類:Unsafe(提供CAS操作)和LockSupport(提供park/unpark操作)。因此,LockSupport可謂構建concurrent包的基礎之一。理解concurrent包,就從這裏開始。

兩個重點

  • 操作對象

歸根結底,LockSupport調用的Unsafe中的native代碼: 

public native void unpark(Thread jthread); 
public native void park(boolean isAbsolute, long time); 

兩個函數聲明清楚地說明了操作對象:park函數是將當前Thread阻塞,而unpark函數則是將另一個Thread喚醒。

與Object類的wait/notify機制相比,park/unpark有兩個優點:1. 以thread爲操作對象更符合阻塞線程的直觀定義;2. 操作更精準,可以準確地喚醒某一個線程(notify隨機喚醒一個線程,notifyAll喚醒所有等待的線程),增加了靈活性。

  • 關於許可

在上面的文字中,我使用了阻塞和喚醒,是爲了和wait/notify做對比。其實park/unpark的設計原理核心是“許可”。park是等待一個許可。unpark是爲某線程提供一個許可。如果某線程A調用park,那麼除非另外一個線程調用unpark(A)給A一個許可,否則線程A將阻塞在park操作上。

有一點比較難理解的,是unpark操作可以再park操作之前。也就是說,先提供許可。當某線程調用park時,已經有許可了,它就消費這個許可,然後可以繼續運行。這其實是必須的。考慮最簡單的生產者(Producer)消費者(Consumer)模型:Consumer需要消費一個資源,於是調用park操作等待;Producer則生產資源,然後調用unpark給予Consumer使用的許可。非常有可能的一種情況是,Producer先生產,這時候Consumer可能還沒有構造好(比如線程還沒啓動,或者還沒切換到該線程)。那麼等Consumer準備好要消費時,顯然這時候資源已經生產好了,可以直接用,那麼park操作當然可以直接運行下去。如果沒有這個語義,那將非常難以操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章