更新時間:2020-11-06 17:40:30 來源:動力節點 瀏覽2342次
在Java多線程中,線程鎖的存在是為了解決資源占用的問題,保證同一時間一個對象只有一個線程在訪問,以此來保證數據的安全性。然而,線程鎖種類繁多,很多時候我們容易混淆概念,本文我們一起來看看線程鎖分類,詳細區分一下線程鎖的種類。
從其它等待中的線程是否按順序獲取鎖的角度劃分。
公平鎖:是指多個線程在等待同一個鎖時,必須按照申請鎖的先后順序來一次獲得鎖。
公平鎖的好處是等待鎖的線程不會餓死,但是整體效率相對低一些;非公平鎖的好處是整體效率相對高一些,但是有些線程可能會餓死或者說很早就在等待鎖,但要等很久才會獲得鎖。其中的原因是公平鎖是嚴格按照請求所的順序來排隊獲得鎖的,而非公平鎖時可以搶占的,即如果在某個時刻有線程需要獲取鎖,而這個時候剛好鎖可用,那么這個線程會直接搶占,而這時阻塞在等待隊列的線程則不會被喚醒。
在Java中,公平鎖可以通過 new ReentrantLock (true) 來實現;非公平鎖可以通過 new ReentrantLock (false) 或者默認構造函數 new ReentrantLock () 實現。
從能否有多個線程持有同一把鎖的角度劃分
互斥鎖的概念非常簡單,也就是我們常說的同步,即一次最多只能有一個線程持有的鎖,當一個線程持有該鎖的時候其它線程無法進入上鎖的區域。在 Java 中 synchronized 就是互斥鎖,從宏觀概念來講,互斥鎖就是通過悲觀鎖的理念引出來的,而非互斥鎖則是通過樂觀鎖的概念引申的。
從一個線程能否遞歸獲取自己的鎖的角度劃分
我們知道,一條線程若想進入一個被上鎖的區域,首先要判斷這個區域的鎖是否已經被某條線程所持有。如果鎖正在被持有那么線程將等待鎖的釋放,但是這就引發了一個問題,我們來看這樣一段簡單的代碼:
public class ReentrantDemo {
private Lock mLock;
public ReentrantDemo(Lock mLock) {
this.mLock = mLock;
}
public void outer() {
mLock.lock();
inner();
mLock.unlock();
}
public void inner() {
mLock.lock();
// do something
mLock.unlock();
}
}
當線程 A 調用 outer () 方法的時候,會進入使用傳進來 mlock 實例來進行 mlock.lock () 加鎖,此時 outer () 方法中的這片區域的鎖 mlock 就被線程 A 持有了,當線程 B 想要調用 outer () 方法時會先判斷,發現這個 mlock 這把鎖被其它線程持有了,因此進入等待狀態。我們現在不考慮線程 B,單說線程 A,線程 A 進入 outer () 方法后,它還要調用 inner () 方法,并且 inner () 方法中使用的也是 mlock () 這把鎖,于是接下來有趣的事情就來了。按正常步驟來說,線程 A 先判斷 mlock 這把鎖是否已經被持有了,判斷后發現這把鎖確實被持有了,但是可笑的是,是 A 自己持有的。那你說 A 能否在加了 mlock 鎖的 outer () 方法中調用加了 mlock 鎖的 inner 方法呢?答案是如果我們使用的是可重入鎖,那么遞歸調用自己持有的那把鎖的時候,是允許進入的。
可重入鎖:可以再次進入方法 A,就是說在釋放鎖前此線程可以再次進入方法 A(方法 A 遞歸)。
不可重入鎖(自旋鎖):不可以再次進入方法 A,也就是說獲得鎖進入方法 A 是此線程在釋放鎖前唯一的一次進入方法 A。
悲觀鎖是就是悲觀思想,即認為讀少寫多,遇到并發寫的可能性高,每次去拿數據的時候都認為別人會修改,所以每次在讀寫數據的時候都會上鎖,這樣別人想讀寫這個數據就會 block 直到拿到鎖。java 中的悲觀鎖就是 Synchronized,AQS 框架下的鎖則是先嘗試 cas 樂觀鎖去獲取鎖,獲取不到,才會轉換為悲觀鎖,如 RetreenLock。
樂觀鎖是一種樂觀思想,即認為讀多寫少,遇到并發寫的可能性低,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,采取在寫時先讀出當前版本號,然后加鎖操作(比較跟上一次的版本號,如果一樣則更新),如果失敗則要重復讀 - 比較 - 寫的操作。
共享鎖和排它鎖多用于數據庫中的事物操作,主要針對讀和寫的操作。而在 Java 中,對這組概念通過 ReentrantReadWriteLock 進行了實現,它的理念和數據庫中共享鎖與排它鎖的理念幾乎一致,即一條線程進行讀的時候,允許其他線程進入上鎖的區域中進行讀操作;當一條線程進行寫操作的時候,不允許其他線程進入進行任何操作。即讀 + 讀可以存在,讀 + 寫、寫 + 寫均不允許存在
共享鎖:也稱讀鎖或 S 鎖。如果事務 T 對數據 A 加上共享鎖后,則其他事務只能對 A 再加共享鎖,不能加排它鎖。獲準共享鎖的事務只能讀數據,不能修改數據。
排它鎖:也稱獨占鎖、寫鎖或 X 鎖。如果事務 T 對數據 A 加上排它鎖后,則其他事務不能再對 A 加任何類型的鎖。獲得排它鎖的事務即能讀數據又能修改數據。
總而言之,線程鎖分類分為這五類,公平鎖與非公平鎖,互斥鎖,重入鎖(遞歸鎖)與不可重入鎖,(自旋鎖)悲觀鎖與樂觀鎖,共享鎖與排它鎖本文中涉及到的這5類的線程鎖幾乎涵蓋了所有的線程鎖,也對每個線程鎖的用法和定義做出了說明,摘錄了本站中多線程教程中的部分內容,是掌握多線程線程鎖種類的必學內容,為我們后面學習多線程的更多內容打下堅實的基礎。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習