ReentrantLock可重入鎖的原理及使用場景


摘要

從使用場景的角度出發來介紹對ReentrantLock的使用,相對來說容易理解一些。

場景1:如果已加鎖,則不再重復加鎖

a、忽略重復加鎖。
b、用在界面交互時點擊執行較長時間請求操作時,防止多次點擊導致后台重復執行(忽略重復觸發)。

以上兩種情況多用於進行非重要任務防止重復執行,(如:清除無用臨時文件,檢查某些資源的可用性,數據備份操作等)

if (lock.tryLock()) {  //如果已經被lock,則立即返回false不會等待,達到忽略操作的效果 
    try {
    //操作
    } finally {
      lock.unlock();
    }
}

場景2:如果發現該操作已經在執行,則嘗試等待一段時間,等待超時則不執行(嘗試等待執行)

這種其實屬於場景2的改進,等待獲得鎖的操作有一個時間的限制,如果超時則放棄執行。
用來防止由於資源處理不當長時間占用導致死鎖情況(大家都在等待資源,導致線程隊列溢出)。

try {
    if (lock.tryLock(5, TimeUnit.SECONDS)) {  //如果已經被lock,嘗試等待5s,看是否可以獲得鎖,如果5s后仍然無法獲得鎖則返回false繼續執行
        try {
        //操作
        } finally {
          lock.unlock();
        }
     }
} catch (InterruptedException e) {
   e.printStackTrace(); //當前線程被中斷時(interrupt),會拋InterruptedException                 
}

場景3:如果發現該操作已經加鎖,則等待一個一個加鎖(同步執行,類似synchronized)

這種比較常見大家也都在用,主要是防止資源使用沖突,保證同一時間內只有一個操作可以使用該資源。
但與synchronized的明顯區別是性能優勢(伴隨jvm的優化這個差距在減小)。同時Lock有更靈活的鎖定方式,公平鎖與不公平鎖,而synchronized永遠是公平的。

這種情況主要用於對資源的爭搶(如:文件操作,同步消息發送,有狀態的操作等)

ReentrantLock默認情況下為不公平鎖

private ReentrantLock lock = new ReentrantLock(); //參數默認false,不公平鎖
private ReentrantLock lock = new ReentrantLock(true); //公平鎖
try {
    lock.lock(); //如果被其它資源鎖定,會在此等待鎖釋放,達到暫停的效果
   //操作
} finally {
    lock.unlock();
}

不公平鎖與公平鎖的區別:

公平情況下,操作會排一個隊按順序執行,來保證執行順序。(會消耗更多的時間來排隊)
不公平情況下,是無序狀態允許插隊,jvm會自動計算如何處理更快速來調度插隊。(如果不關心順序,這個速度會更快)

場景4:可中斷鎖

synchronized與Lock在默認情況下是不會響應中斷(interrupt)操作,會繼續執行完。lockInterruptibly()提供了可中斷鎖來解決此問題。(場景3的另一種改進,沒有超時,只能等待中斷或執行完畢)

這種情況主要用於取消某些操作對資源的占用。如:(取消正在同步運行的操作,來防止不正常操作長時間占用造成的阻塞)

try {
    lock.lockInterruptibly();
    //操作
} catch (InterruptedException e) {
    e.printStackTrace();
} finally {
    lock.unlock();
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM