Java 多線程(三)- Lock 和 ReentrantLock

Lock

Lock接口定義了一組抽象的加鎖操作:

public interface Lock {
    //獲取鎖,會(huì)一直等待
    void lock();    
    //獲取鎖,否則一直等待,但是等待狀態(tài)可以被其他線程中斷
    void lockInterruptibly() throws InterruptedException;
    //嘗試獲得鎖,沒(méi)搶到直接返回失敗
    boolean tryLock();      
    //嘗試獲取鎖,沒(méi)搶到則會(huì)等待一段時(shí)間,等待狀態(tài)可以被其他線程中斷
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    //釋放鎖
    void unlock();
    //生成鎖的條件變量,線程獲取鎖后,可以等待或者通知該條件變量
    Condition newCondition();
}

與內(nèi)置的 Monitor 鎖(也叫內(nèi)部鎖,內(nèi)置鎖)不同,Lock 提供了多種獲取鎖的方式(無(wú)條件的,可輪詢的,定時(shí)的以及可中斷的),所有的加鎖和解鎖的方法都是顯示的。

Lock 的實(shí)現(xiàn)類必須提供與內(nèi)部鎖相同的內(nèi)存可見(jiàn)性,但在加鎖語(yǔ)義,調(diào)度算法,順序保證以及性能特性有所不同。

可重入鎖 ReentrantLock

ReentrantLock 實(shí)現(xiàn)了 Lock 接口,并提供了與 synchronized 相同的互斥和內(nèi)存可見(jiàn)性,ReentrantLock 并不是替代內(nèi)置鎖的方法,而是當(dāng)內(nèi)置鎖機(jī)制不適用時(shí),作為一種可以選擇的補(bǔ)充的高級(jí)功能。

對(duì)比 synchronized

ReentrantLock 是 synchronized 的功能補(bǔ)充,它們之間的差異可以用下表表示:

| synchronized | ReentrantLock
------------- | ------------- | -------------
獲取鎖方式 | 搶鎖失敗只能無(wú)限等待 | 提供多種等待鎖方式,可以無(wú)限等待
| | 可以限制等待超時(shí)
| | 等待時(shí)可以被中斷
| | 可以無(wú)阻塞嘗試獲取鎖
等待線程調(diào)度 | 未知,視 JVM 實(shí)現(xiàn) | 公平鎖:FIFO,按照進(jìn)入同步隊(duì)列順序
| | 非公平鎖:第一次獲取鎖時(shí)有機(jī)會(huì)插隊(duì)
編程便利性 | 獲取鎖/等待鎖/釋放鎖都有內(nèi)部實(shí)現(xiàn),使用便利 | 需要顯示獲取鎖,釋放鎖,切記要捕捉 exception, 在 finally 中釋放鎖
性能 | 略低,Java6 后有顯著提高 | 較高,Java6 后差距減小
調(diào)試 | 線程轉(zhuǎn)儲(chǔ)中給出哪些調(diào)用幀獲得哪些鎖 | Java6 后提供管理和調(diào)試接口,鎖需要通過(guò)該接口注冊(cè),相關(guān)加鎖信息出現(xiàn)在線程轉(zhuǎn)儲(chǔ)中

未來(lái)更可能提升 synchronized 性能,因?yàn)?synchronized 是 JVM 內(nèi)置屬性,它能執(zhí)行一些優(yōu)化,比如增加鎖的粒度來(lái)消除內(nèi)置鎖的同步,對(duì)于類庫(kù)里的 ReentrantLock 則優(yōu)化余地不大。所以綜合未來(lái)性能,調(diào)試,特別是編程便利性來(lái)說(shuō),synchronized 是使用時(shí)的第一選擇,只有當(dāng)它的功能不滿足,或者程序運(yùn)行在 Java5 或之前,才考慮 ReentrantLock。

公平性

ReentrantLock 的構(gòu)造函數(shù)中提供兩個(gè)公平性選擇:創(chuàng)建一個(gè)非公平(默認(rèn))的鎖,或者公平鎖。

公平鎖

線程按照他們發(fā)出請(qǐng)求的順序來(lái)獲得鎖。如果有另一個(gè)線程持有這個(gè)鎖或者有其他線程在隊(duì)列中等待這個(gè)鎖,那么新發(fā)出請(qǐng)求的線程將放入隊(duì)列中。

但是即便對(duì)于公平鎖而已,可輪詢的 tryLock 仍然會(huì)有可能插隊(duì)。

非公平鎖

非公平鎖允許“插隊(duì)”:當(dāng)一個(gè)線程請(qǐng)求非公平的鎖時(shí),如果在發(fā)出請(qǐng)求的同時(shí)該鎖的狀態(tài)變?yōu)榭捎茫敲催@個(gè)線程將跳過(guò)排隊(duì)隊(duì)列,直接獲取這個(gè)鎖。

只有當(dāng)鎖被某個(gè)線程持有時(shí),新發(fā)出請(qǐng)求的線程才會(huì)被放入隊(duì)列中。

為什么要將非公平鎖作為默認(rèn)鎖,因?yàn)樵趯?shí)際應(yīng)用中,確保被阻塞的線程能夠最終獲得鎖就可以了,絕對(duì)的公平產(chǎn)生的開(kāi)銷也較大,絕大多數(shù)情況下,非公平鎖的性能要高于公平鎖。

內(nèi)部實(shí)現(xiàn)

可以把 ReentrantLock 想象成代理模式,其中最核心的加鎖/解鎖等操作其實(shí)都是由 Sync 對(duì)象完成的,Sync 的 acquire 系列接口實(shí)現(xiàn)加鎖, release 系列接口實(shí)現(xiàn)解鎖。對(duì)于公平鎖和非公平鎖,分別由 FairSync 和 NonfairSync 實(shí)現(xiàn)。它們之間的類圖關(guān)系,如下圖所示:

類關(guān)系

其中最核心的部分是 AbstractQueuedSynchronizer,簡(jiǎn)稱 AQS。這個(gè)類也是其他同步類的基類,AQS 是一個(gè)用戶構(gòu)建鎖和同步器的框架,許多同步器都可以通過(guò) AQS 快速的構(gòu)造出來(lái)。不僅是 ReentrantLock, 也包括 Semaphore, CountDownLatch, ReentrantReadWriteLock, SynchronouszQueue 和 FurtureTask。

因?yàn)槠?,最核心?AQS 不妨放到下篇來(lái)記錄。

最佳編程模式
class X {
    private final ReentrantLock lock = new ReentrantLock();
    // ...

    public void m() {
        lock.lock();  // block until condition holds
        try {
            // ... method body
        } finally {
            lock.unlock();
        }
    }
}

切記 finally 中釋放鎖。

內(nèi)容來(lái)源

Java 并發(fā)編程實(shí)戰(zhàn)

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

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

  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來(lái)是分開(kāi)三篇的,后來(lái)想想還是整...
    coder_pig閱讀 1,772評(píng)論 2 17
  • 1.解決信號(hào)量丟失和假喚醒 public class MyWaitNotify3{ MonitorObject m...
    Q羅閱讀 1,015評(píng)論 0 1
  • ?既然java內(nèi)置了synchronized,為什么還要出現(xiàn)lock呢??由于synchronized的并發(fā)是阻塞...
    扈扈哈嘿閱讀 986評(píng)論 0 1
  • 不管生活,還是工作時(shí)時(shí)都有雙贏的身影。對(duì)待家人,同事,朋友都應(yīng)有以心換心,不能自私自利,用雙贏的心態(tài)去面對(duì)和溝通,...
    紫色豐信子閱讀 183評(píng)論 0 1
  • 小時(shí)候的老家沒(méi)大門(mén),院子是泥土的那種。現(xiàn)在想來(lái)那是我最美好的回憶的全部。兒時(shí)的想法很單純,院子這么大,好像世界就這...
    微笑的微笑著閱讀 281評(píng)論 0 0

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