Lock和Condition(上):隱藏在併發包中的管程
1)管程在SDK包中是怎樣實現的?
-
靠Lock和Condition介面,Lock用來解決互斥的問題 ,Condition用來解決同步的問題。
2)java語言層面已經有sychronized來 實現管程了,那為什麼我們的sdk工具包中還要再實現一遍管程,直接用sychronized不就行了嗎?
-
sychronized這個語言層面的設計是有瑕疵的,我們說解決死鎖有個方法:破壞不可強行剝奪條件。那我們的sychrnized他如果獲取不到資源,他會帶著已申請到的資源進入阻塞佇列去排隊,如果他帶進去的資源剛好是另外一個執行緒苦苦等待的,那就可能造成死鎖 。
3)怎樣去優化我們synchronized修飾的執行緒帶著資源進阻塞佇列排隊這個問題呢?
-
首先這個 排隊執行緒要 能夠收得到訊息 ,對應計算機層面就是響應中斷。
-
其次啊,要讓它能夠有個超時機制,獲取不到進一步資源的話,再等等嘛,實在等不到返回個錯誤也行,就是不要帶著已有資源去阻塞佇列睡大覺 。讓別人也不好過。
-
最後可不可以設計成如果獲取不到進一步的資源,不要進入阻塞佇列,而是直接返回,並且交出已有資源。
4)上面的三個設計方案對應到我們的SDK工具包之中是怎樣實現的?
// 支援中斷的API
void lockInterruptibly()
throws InterruptedException;
// 支援超時的API
boolean tryLock(long time, TimeUnit unit)
throws InterruptedException;
// 支援非阻塞獲取鎖的API
boolean tryLock();
5)我們說sychronized保證可見性是根據happen-before規則,那現在工具包中的這些設計是如何保證可見性的呢?
-
ReentrantLock底層有一個volatile型別的成員變數state。加鎖和解鎖之前都去讀一下這個變數,從而就利用volitile來保證可見性。
6)什麼是可重入鎖呢?
-
可以巢狀使用的鎖
A加鎖{
A又加鎖{
}
}
7)什麼是公平鎖和非公平鎖?
-
在佇列中排隊,如果cpu空閒的時候,是排在第一個的 先去 用那就是公平鎖,否則就是不公平的鎖。
-
對應到具體程式碼,我們的reentrantLock可以帶布林型別的引數,true的話就是一把公平鎖,false或者不填就是一把不公平的鎖 。
8)關於鎖,老前輩們有哪些最佳實踐方案?
-
在更新一個物件的共享變數的時候需要上把鎖。
-
在讀取一個共享變數的時候也需要上把鎖。
-
在呼叫其它物件的方法的時候千萬不要用鎖,萬一他這個物件方法裡面有一些操作,可能會造成死鎖。