本文基于java version "1.8.0_77"
LockSupport(java.util.concurrent.locks.LockSupport)是Java中底層類,提供了基本的線程同步原語。JUC中同步框架核心AQS(AbstractQueuedSynchronizer),就是通過使用LockSupport來實現線程的阻塞與喚醒的。我們先了解一下LockSupport類,為了解AQS做準備。
LockSupport中的兩個核心方法:
- public static void park()
- public static void unpark(Thread thread)
park
譯為“停車”,官方文檔意為:許可。為了方便理解,在這里我們可以理解為阻塞,等待,掛起
,而unpark
我們理解為喚醒,恢復
。
這些字眼是不是很熟悉?我們在使用多線程的時候會調用object.wait()
和object.notify(),object.notifyall()
來達到等待和喚醒的功能。此處我們可以比較著來學習。
與object的先wait,后notify
方法不同的是,park與unpark無需擔心調用時序問題,可以先park,后unpark
,也可以先park,后park
。還有一點需要注意,多次連續給一個線程下發許可,但是這中間并沒有消耗的情況下,只會保留一個許可。(可以理解為許可的只有有
或沒有
之分,而沒有數量的多少)
當線程A調用park()
后,會申請一個許可證:
- 如果沒有許可,會阻塞當前線程,直至有其他線程下發許可(LockSupport.unpark(線程A))。
- 如果此時已經能夠有一個許可,則可以繼續往下執行代碼。
我們來看下面的例子:
public static void main(String[] args) {
LockSupport.park();// 獲取許可
System.out.println("END");
}
運行上述代碼,會發現,該代碼不會打印END。因為當前線程申請一個許可而沒有線程給他許可,故一直阻塞,進程不會關閉。
多線程中通信的例子:
結果:
上圖中可以看到,boyThread通過park阻塞線程,直至girlThread調用unpark喚醒。
看一個特殊例子:
結果:
可以看到,即便是已經下發了4個許可,但是實際上只有一個許可,也就是說許可存在的個數只有0或1。
其他方法:
-
void park(Object blocker)
阻塞線程時添加附加信息,用來記錄線程是被誰堵塞的,程序出現問題時候,通過線程監控分析工具可以找出問題所。 -
void parkNanos(long nanos)
參數為阻塞超時時間,超時時間過后,如果還沒有下發許可,則自動喚醒 -
void parkNanos(Object blocker, long nanos)
同上,方法重載 -
void parkUntil(long deadline)
參數為阻塞截止時間,為絕對時間,到達時間后,如果還沒有下發許可,則自動喚醒 -
void parkUntil(Object blocker, long deadline)
同上,方法重載
與Object中wait和notify的區別
- 比wait/notify更加輕便靈活。LockSupport直接操作線程,而wait/notify則是需要一個Object對線程進行操作。
- 不依賴監視器(鎖)。wait/notify需要在synchronized中進行調用,它首先需要獲取到鎖,才能進行下面的操作。而LockSupport則是直接進行調用。(synchronized與wait/notify配合使用,ReentrantLock與Condition配合使用。而Condition就是使用LockSupport實現等待與喚醒的)
End