最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的ReadWriteLock讀寫鎖實例詳解

 更新時間:2026年03月07日 10:28:53   作者:懶惰蝸牛  
Java中的ReadWriteLock讀寫鎖,它是一種讀寫分離的鎖機制,適用于讀多寫少的場景,本文通過實例代碼給大家介紹Java中的ReadWriteLock讀寫鎖,感興趣的朋友跟隨小編一起看看吧

在之前的文章中,我們已經學習了synchronized和ReentrantLock。通過學習我們知道這兩者都是屬于排它鎖,也叫做互斥鎖。

什么叫互斥鎖呢?就是不管哪個線程去讀取數據還是修改數據,只要他持有鎖,那其他的線程就必須等著。

這在大多數情況下肯定是線程安全的,沒什么問題。

但是在實際的開發(fā)過程中,有一些很常見的讀多寫少的場景。像配置信息,熱點數據的緩存。這些數據實際上被大量的線程進行頻繁的讀取,而只在極少的情況下會去修改。

在這類場景下,如果讀取操作也使用排他鎖,想想都會降低系統性能。因為讀取操作本身并不會改變數據,多個線程同時讀取同一個數據是完全安全的。

那有沒有一種鎖能把讀取和寫入區(qū)別開呢?

那肯定是有的,JUC包下的ReadWriteLock就是為解決這個問題而生的。

今天我們就一起來看看ReadWriteLock。

一、什么是ReadWriteLock

ReadWriteLock是java.util.concurrent.locks中的一個接口。既然是接口,那他就不是一把具體的鎖。

可以把他理解成一個鎖的管理者。他內部管理了兩把相互關聯的鎖:

一個讀取鎖,也叫做共享鎖。

一個寫入所,也叫排它鎖。

再提一句,源碼中的注釋真的有必要去看一看,不管是學習前還是學習后,盡量都去閱讀下源碼及注釋。

ReentrantReadWriteLock是ReadWriteLock接口最常用的實現類。

這套鎖機制有以下的核心原則:

讀-讀 共享:多個線程可以同時持有讀取鎖,進行并發(fā)讀取。

讀-寫 互斥:當有線程持有讀取鎖時,寫入線程必須等待。

寫-讀 互斥:當有線程持有寫入鎖時,所有其他線程(不管讀寫)都必須等待。

寫-寫 互斥:當有線程持有寫入鎖時,其他寫入線程也必須等待。

其實很好理解,讀鎖大家用,寫鎖只能一個人用。

大家都是讀,其樂融融,隨便讀。

我在讀,你想寫,你得等著,等我讀完了,不然就存在邊讀邊寫的詭異事情。

我在寫,你想讀或者你也想寫,那都得等著,不然又會混亂了。

簡單的總結就是:讀鎖大家用,寫鎖我獨占。

二、讀寫鎖使用

我們通過一個小案例來看一下讀寫鎖的使用:

package com.lazy.snail.day40;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
 * @ClassName Day40Demo
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/8/12 9:52
 * @Version 1.0
 */
public class Day40Demo {
    private final Map<String, String> map = new HashMap<>();
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock rLock = rwLock.readLock();
    private final Lock wLock = rwLock.writeLock();
    public String get(String key) {
        rLock.lock();
        try { return map.get(key); }
        finally { rLock.unlock(); }
    }
    public void put(String key, String value) {
        wLock.lock();
        try { map.put(key, value); }
        finally { wLock.unlock(); }
    }
}

之前的集合框架學習中,我們已經知道HashMap自身不是線程安全的,但是我們可以用鎖把所有的訪問都包起來。來保證線程安全。

rwLock是我們創(chuàng)建的讀寫鎖管理器,生成兩把關聯的鎖:讀鎖、寫鎖。

rLock和wLock分別取出讀鎖和寫鎖。

get方法代表只讀路徑,也就是讀取。在沒有線程持有寫鎖/等待寫的時候,多個線程可以同時獲取讀鎖。

在持鎖期間進行讀?。╩ap.get()),避免了跟寫線程并發(fā)導致的數據競爭。

最后在finally里面釋放鎖。

put方法代表寫路徑,也就是寫入。

寫鎖是獨占的。只要有線程持有寫鎖,其他讀/寫都得等;反過來,只要有讀鎖在,寫鎖也進不來。

唯一寫入口(map.put),確保不會出現同時寫或讀寫交疊。

同樣在finally中釋放鎖。

三、內部原理

3.1 鎖實現及獲取

ReentrantReadWriteLock內部并不是維護兩把完全獨立的鎖,而是用一個32位int變量state同時記錄讀寫狀態(tài):

其中高16位表示讀鎖計數,允許多個線程同時增加。

低16位表示寫鎖計數,同一個線程可以重入。

ReentrantReadWriteLock中相關的核心常量:

獲取寫鎖:

1.檢查state是不是為0。如果不是0,意味著要么有讀鎖存在 (readCount > 0),要么已經有其他線程持有了寫鎖 (writeCount > 0)。

2.如果state不是0,但持有寫鎖的是當前線程,就可以重入,把writeCount加1。

3.如果state是0,那么當前線程可以獲取寫鎖,把writeCount加1,把當前線程設置成鎖的持有者。

獲取讀鎖:

1.檢查是不是存在寫鎖 (writeCount > 0),且持有寫鎖的不是當前線程。如果是,則獲取失敗,進入等待隊列。

2.如果沒有寫鎖,或者寫鎖被當前線程持有,那么當前線程可以獲取讀鎖,通過CAS操作把readCount加1。

3.2 公平策略

ReentrantReadWriteLock跟ReentrantLock一樣,也支持公平和非公平兩種模式。

非公平鎖:new ReentrantReadWriteLock()和new ReentrantReadWriteLock(false)都是非公平鎖構造。允許新來的線程插隊。舉個例子,當寫鎖被釋放的時候,如果等待隊列里有讀線程和寫線程,同時又有一個新的讀線程請求鎖,那么這個新的讀線程可能優(yōu)先獲得鎖。從例子就能看出優(yōu)點肯定是吞吐量更高,但可能會導致寫線程饑餓。

公平鎖:new ReentrantReadWriteLock(true)。這種模式就嚴格按照線程在等待隊列里的FIFO順序來分配鎖。如果隊列頭部是寫線程在等待,那所有后來的讀鎖請求都必須排隊。優(yōu)點就是能防止饑餓,保證公平性,一般情況下性能會低于非公平鎖,畢竟要維持公平性。

3.3 鎖升降級

鎖降級指的是線程在持有寫鎖的情況下,繼續(xù)獲取讀鎖,然后釋放寫鎖。

鎖升級指的是線程在持有讀鎖的情況下,去獲取寫鎖。ReentrantReadWriteLock是不支持的。

鎖降級

考慮這樣一個場景,如果有一個線程更新了共享數據后,還需要讀取這些數據處理其他業(yè)務,但這個時候已經不希望再獨占資源,而是允許其他讀線程進來。

wLock.lock(); // 獲取寫鎖
try {
    // 修改數據...
    map.put("name", "懶惰蝸牛");
    // 鎖降級:在持有寫鎖的情況下獲取讀鎖
    rLock.lock();
    // 釋放寫鎖(這個時候仍然持有讀鎖)
    // 其他線程現在可以獲取讀鎖了
    wLock.unlock();
    // 使用讀鎖狀態(tài)讀取數據,執(zhí)行后續(xù)操作...
    // 保證了在讀取期間,數據不會被其他寫線程修改
    System.out.println("讀取數據: " + map.get("name"));
} finally {
    // 釋放讀鎖
    rLock.unlock(); 
}

鎖升級

為什么不支持鎖升級,如果兩個線程(T1, T2)同時持有讀鎖,然后他們都嘗試升級成寫鎖。T1要等待T2釋放讀鎖,而T2也要等待T1釋放讀鎖,就這樣相互等著,最后就形成死鎖了。

所以必須先rLock.unlock(),然后再wLock.lock()。但還是要注意的是,在釋放讀鎖和獲取寫鎖的間隙,數據可能被其他線程修改,原子性被破壞了,這就需要我們自己的業(yè)務邏輯來處理。

四、小結

目前我們已經接觸了synchronized、ReentrantLock和ReentrantReadWriteLock。

下面對這三種形式的鎖用表格進行清晰的對比:

特性synchronizedReentrantLockReentrantReadWriteLock
鎖類型互斥鎖互斥鎖讀寫分離鎖(共享/互斥)
底層實現JVM指令AQSAQS
公平性非公平可選(默認非公平)可選(默認非公平)
可中斷不可中斷可中斷可中斷
嘗試獲取鎖不支持支持 (tryLock)支持 (tryLock)
Conditionwait/notifyCondition僅寫鎖支持Condition
適用場景簡單同步代碼塊需高級功能的復雜同步讀多寫少的場景

每種形式的鎖都有各自的優(yōu)缺點,都有自己的應用場景。

到此這篇關于Java中的ReadWriteLock讀寫鎖的文章就介紹到這了,更多相關Java ReadWriteLock讀寫鎖內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Spring中@ControllerAdvice注解的用法解析

    Spring中@ControllerAdvice注解的用法解析

    這篇文章主要介紹了Spring中@ControllerAdvice注解的用法解析,顧名思義,@ControllerAdvice就是@Controller 的增強版,@ControllerAdvice主要用來處理全局數據,一般搭配@ExceptionHandler、@ModelAttribute以及@InitBinder使用,需要的朋友可以參考下
    2023-10-10
  • Java?awt-對話框簡單實現方式

    Java?awt-對話框簡單實現方式

    這篇文章主要介紹了Java?awt-對話框簡單實現方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java使用application.property讀取文件里面的值

    Java使用application.property讀取文件里面的值

    本文通過實例代碼給大家介紹了Java使用application.property讀取文件里面的值,需要的朋友可以參考下
    2018-10-10
  • java微信紅包實現算法

    java微信紅包實現算法

    這篇文章主要為大家詳細介紹了java微信紅包實現算法,列出紅包的核心算法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • Spring?注入靜態(tài)對象使用三種方式示例

    Spring?注入靜態(tài)對象使用三種方式示例

    這篇文章主要為大家介紹了Spring注入靜態(tài)對象使用的三種方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • ElasticSearch學習之文檔API相關操作

    ElasticSearch學習之文檔API相關操作

    這篇文章主要為大家介紹了ElasticSearch學習之文檔API相關操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • Java的信號量semaphore講解

    Java的信號量semaphore講解

    這篇文章主要介紹了Java的信號量semaphore講解,Semaphore底層是基于AbstractQueuedSynchronizer來實現的,Semaphore稱為計數信號量,它允許n個任務同時訪問某個資源,需要的朋友可以參考下
    2023-12-12
  • Java?C++題解leetcode904水果成籃

    Java?C++題解leetcode904水果成籃

    這篇文章主要為大家介紹了Java?C++題解leetcode904水果成籃示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • Springboot項目基于Devtools實現熱部署步驟詳解

    Springboot項目基于Devtools實現熱部署步驟詳解

    這篇文章主要介紹了Springboot項目基于Devtools實現熱部署,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • 純Java環(huán)境下實現將在線地圖路網數據轉為GeoJSON與WKT

    純Java環(huán)境下實現將在線地圖路網數據轉為GeoJSON與WKT

    這篇文章主要為大家詳細介紹了如何純Java環(huán)境下實現將在線地圖路網數據轉為GeoJSON與WKT,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下
    2026-02-02

最新評論

深水埗区| 卢龙县| 瓮安县| 曲松县| 建湖县| 来宾市| 白朗县| 元朗区| 阜城县| 鄂托克前旗| 贵州省| 达州市| 望谟县| 宁南县| 施秉县| 双峰县| 日照市| 武夷山市| 郑州市| 上高县| 长岛县| 禹州市| 九江县| 鄂托克前旗| 丰城市| 临澧县| 广饶县| 家居| 施秉县| 织金县| 昌邑市| 喀什市| 监利县| 高碑店市| 澄江县| 舟山市| 大厂| 祁东县| 时尚| 乳山市| 加查县|