Java線程-鎖的分類(四)

一、前言

Java中的鎖有各種特性,比如可重入與不可重入,公平與非公平等,也可以根據(jù)這些特性進行分類。

二、可重入鎖
  1. 當某個線程請求一個由其他線程持有的鎖的時,發(fā)出請求的的線程就會阻塞。但當一個線程再次請求自己持有的對象鎖時,如果能請求成功,說明這個鎖是可重入的。也就是說線程可以重復(fù)的獲得已經(jīng)持有的鎖;
  2. 拿synchronized來說,synchronized的鎖是原子性的,也是可重入的,因此一個線程調(diào)用synchronized方法的同時在其方法體內(nèi)部調(diào)用該對象的另一個synchronized方法將不會進入阻塞狀態(tài),也就是說一個線程得到對象鎖后再次請求該對象鎖是允許的,這就是synchronized的可重入性。

看一段代碼:

public class ThreadTest extends SuperClass {
    public synchronized void test(Thread thread) {
        System.out.println(thread.getName());
        super.test();
    }
}
class SuperClass {
    public synchronized void test() {
        System.out.println(Thread.currentThread().getName());
    }
}

??子類重寫了父類的test方法,然后調(diào)用父類的方法,此時如果沒有可重入的鎖,那么這段代碼將會產(chǎn)生死鎖。因為兩個方法都是synchronized方法,因此每個test方法再執(zhí)行前都會獲取SuperClass對象鎖,然后如果該鎖不是可重入的,那么在調(diào)用super.test方法時將無法獲得SuperClass對象上的鎖,因為這個鎖已經(jīng)被持有,從而線程將永遠停頓下去,等待一個永遠也無法獲得的鎖。

  1. 可重入鎖的一種實現(xiàn)方式是為每個鎖關(guān)聯(lián)一個計數(shù)值和一個所有者線程。當計數(shù)器為0時,這個鎖就被認為是沒有被任何線程持有,當線程請求一個未被持有的鎖時,JVM將記下鎖的持有者,并且將獲取計數(shù)值置為1,如果同一個線程再次獲取這個鎖,計數(shù)值遞增,而當線程退出同步代碼塊時,計數(shù)器會相應(yīng)的遞減,當計數(shù)器為0時,該鎖被釋放。
  2. 可重入鎖,有時也被稱為遞歸鎖,也就是說外層代碼獲取該鎖之后,內(nèi)層遞歸函數(shù)仍然可以獲得該鎖,JAVA中, ReentrantLocksynchronized 都是 可重入鎖;
  3. 可重入鎖的最大作用就是可以避免死鎖;
二、可中斷鎖
  1. 可中斷鎖,顧名思義就是可以中斷阻塞中的鎖,Java中的synchronized由于不可中斷,不是可中斷鎖,而Lock則是可中斷鎖。
  2. 通俗的來說,如果某一線程A正在執(zhí)行鎖中的代碼,另一線程B正在等待獲取該鎖,可能由于等待時間過長,線程B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在別的線程中中斷它,這種就是可中斷鎖。
三、讀寫鎖

??就是說對資源的訪問操作分為讀鎖和寫鎖,分開來進行。就是因為有了讀寫鎖,才使得多個線程之間的讀操作不會發(fā)生沖突,對應(yīng)的接口是ReadWriteLock,該接口對應(yīng)的實現(xiàn)類是ReentrantReadWriteLock,可以通過對應(yīng)的readLock()方法獲取讀鎖,通過writeLock()方法獲取寫鎖,后續(xù)我們會學(xué)習(xí)到。

四、公平鎖

??公平鎖是說根據(jù)請求鎖的順序來獲取鎖,比如同時有多個線程在等待獲取鎖的時候,最先請求的線程會獲取該鎖(也就是等待時間最長的線程),這種就是公平鎖。非公平鎖就無法保證這點了,但需要注意下:

  1. Java中的synchronized是一種非公平鎖,無法保證最先請求的線程先獲取到鎖,而ReentrantLock和ReentrantReadWriteLock,默認情況下是非公平鎖,但可以設(shè)置為公平鎖,后續(xù)我們學(xué)習(xí)到這里的時候再說。
  2. 對ReentrantLock來說,即使是公平鎖,對于可輪詢的tryLock仍然有可能會出現(xiàn)“插隊”的現(xiàn)象,也就是不按線程請求順序的情況。所以說即使是公平鎖,也不一定能確保線程調(diào)度器是公平的。如果線程調(diào)度器選擇忽略一個線程,而該線程恰好是等待時間最長的那個,那么就沒有機會公平的處理這個鎖了。
  3. 公平鎖的實現(xiàn)需要通過一個隊列來維護線程請求的順序性,并且在進行等待和喚醒線程時存在一定的性能開銷,而非公平性則不用考慮這些,所以大多數(shù)情況下,非公平鎖的性能要高于公平鎖的性能。但當持有鎖的實際相對較長,或者請求鎖的平均時間間隔較長的時候,這時候可以使用公平鎖。

本文參考自:
海子-Java并發(fā)編程-Lock
《Java并發(fā)編程實戰(zhàn)》
《Java核心技術(shù)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 30,282評論 8 265
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 2,303評論 0 14
  • 1.解決信號量丟失和假喚醒 public class MyWaitNotify3{ MonitorObject m...
    Q羅閱讀 1,017評論 0 1
  • 在一個方法內(nèi)部定義的變量都存儲在棧中,當這個函數(shù)運行結(jié)束后,其對應(yīng)的棧就會被回收,此時,在其方法體中定義的變量將不...
    Y了個J閱讀 4,577評論 1 14
  • 突然間有點心疼自己,想蹲下來狠狠的抱抱自己!不知道為什么生活過的竟如此凄慘…… 最近又重現(xiàn)讀了一遍海子的詩:從明天...
    016d6912f64e閱讀 179評論 0 0

友情鏈接更多精彩內(nèi)容