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

關(guān)于ReadWriteLock讀寫鎖的使用及說明

 更新時間:2025年06月30日 09:22:04   作者:找不到、了  
這篇文章主要介紹了關(guān)于ReadWriteLock讀寫鎖的使用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

ReentrantReadWriteLock實現(xiàn)了ReadWriteLock接口。位于java.util.concurrent.locks;

1、普通鎖

讀寫互斥,如ReentrantLock。

1.1、原理

  • 普通鎖是排他鎖(Exclusive Lock):無論讀還是寫,同一時刻只能有一個線程持有鎖。
  • 所有操作互斥:即使多個線程只是讀取數(shù)據(jù),普通鎖也會阻塞其他線程。

代碼示例:

ReentrantLock lock = new ReentrantLock();

void read() {
    lock.lock();
    try {
        // 讀取數(shù)據(jù)
    } finally {
        lock.unlock();
    }
}

void write() {
    lock.lock();
    try {
        // 寫入數(shù)據(jù)
    } finally {
        lock.unlock();
    }
}

1.2、特點

  • 讀線程會阻塞其他讀線程:即使沒有寫操作,讀線程之間也不能并發(fā)。
  • 性能低:在高并發(fā)讀場景下,資源利用率低。

2、ReadWriteLock

讀寫分離機制。

  • 基于 AQS:通過state字段的高位和低位分別管理讀鎖和寫鎖。
  • 共享鎖(Shared):允許多個線程同時讀。
  • 排他鎖(Exclusive):寫操作獨占鎖。

2.1、核心思想

規(guī)則讀鎖與讀鎖不互斥讀鎖與寫鎖互斥。寫鎖與寫鎖互斥。

讀鎖(共享鎖)

  • 多個線程可同時持有讀鎖。
  • 獲取讀鎖時,需確保沒有寫鎖存在。
  • 讀鎖可重入(同一線程多次獲取讀鎖時,state高位增加)。

寫鎖(排他鎖)

  • 寫鎖獨占,阻塞所有讀和寫操作。
  • 寫鎖可重入(同一線程多次獲取寫鎖時,state低位增加)。
  • 寫鎖可降級為讀鎖(但不能升級為寫鎖)。

鎖升級/降級規(guī)則

  • 不允許升級:讀鎖不能直接升級為寫鎖(會破壞公平性,可能導致死鎖)。
  • 允許降級:寫鎖可以降級為讀鎖(需顯式釋放寫鎖后獲取讀鎖)。

代碼示例:

ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
Lock readLock = readWriteLock.readLock();
Lock writeLock = readWriteLock.writeLock();

void read() {
    readLock.lock();
    try {
        // 讀取數(shù)據(jù)(多個線程可同時讀)
    } finally {
        readLock.unlock();
    }
}

void write() {
    writeLock.lock();
    try {
        // 寫入數(shù)據(jù)(獨占)
    } finally {
        writeLock.unlock();
    }
}

為什么讀鎖和寫鎖可以“部分共存”?

  • 讀鎖不阻塞其他讀鎖:因為讀操作不會修改數(shù)據(jù),多個線程讀取共享數(shù)據(jù)是安全的。
  • 寫鎖阻塞所有讀寫:寫操作需要獨占數(shù)據(jù),防止臟讀和數(shù)據(jù)不一致。

2.2、特點

1、高效

適合高并發(fā)讀的場景。

  • 普通鎖:多個讀線程互相阻塞,吞吐量低。
  • 讀寫鎖:多個讀線程可并發(fā)讀取,吞吐量高。

2、緩存讀取和更新

class Cache {
    private Object data;
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    void get() {
        lock.readLock().lock();
        try {
            // 多個線程可同時讀取
            return data;
        } finally {
            lock.readLock().unlock();
        }
    }

    void put(Object newData) {
        lock.writeLock().lock();
        try {
            // 寫入時獨占
            data = newData;
        } finally {
            lock.writeLock().unlock();
        }
    }
}
  • 優(yōu)勢:緩存讀取頻繁,寫入較少,使用讀寫鎖可大幅提升并發(fā)性能。

2.3、鎖共存

寫鎖不能與讀鎖或?qū)戞i共存。具體是為什么,可參考以下數(shù)據(jù)一致性和state字段來進行分析。

1. 數(shù)據(jù)一致性要求

寫操作必須獨占:如果允許寫鎖與讀鎖或?qū)戞i共存,可能導致:

  • 臟讀:讀線程讀到未提交的數(shù)據(jù)。
  • 數(shù)據(jù)不一致:多個寫線程同時修改數(shù)據(jù),導致結(jié)果不可預測。

2. 內(nèi)部實現(xiàn)限制

讀寫鎖的實現(xiàn)

  • 使用一個int類型的state字段,高16位表示讀鎖數(shù)量,低16位表示寫鎖重入次數(shù)。
  • 寫鎖獲取時:必須確保當前沒有讀鎖或?qū)戞i。
  • 讀鎖獲取時:必須確保當前沒有寫鎖。

2.4、關(guān)鍵字段

  • state:高位(32位)表示讀鎖數(shù)量,低位(32位)表示寫鎖重入次數(shù)。
  • readLockwriteLock:分別管理讀鎖和寫鎖的獲取與釋放。

以下是常用的方法:

  • readLock().lock():嘗試獲取共享鎖。
  • writeLock().lock():嘗試獲取排他鎖。
  • readLock().unlock()writeLock().unlock():釋放對應鎖。

2.5、獲取流程

1、寫鎖

  • 檢查當前是否有寫鎖(通過exclusiveCount判斷)。
  • 檢查是否有讀鎖(通過sharedCount判斷)。
  • 如果沒有讀鎖和寫鎖,則設(shè)置寫鎖狀態(tài)。
  • 否則,將線程加入等待隊列。

2、讀鎖

  • 檢查當前是否有寫鎖。
  • 如果沒有寫鎖,則嘗試增加讀鎖計數(shù)。
  • 如果有寫鎖或讀鎖溢出,則將線程加入等待隊列。

小結(jié)

如何選擇哪種鎖,可根據(jù)以下場景進行分析:

選擇普通鎖

  • 數(shù)據(jù)操作簡單(如單次寫入后只讀)。
  • 不需要區(qū)分讀寫操作。

選擇讀寫鎖

  • 讀操作遠多于寫操作(如緩存、配置中心)。
  • 需要提升讀并發(fā)性能。

對比

普通鎖 vsReadWriteLock:

3、寫鎖饑餓

3.1、原因

1. 優(yōu)先級

  • ReentrantReadWriteLock 默認是非公平模式fair=false)。
  • 讀鎖的優(yōu)先級更高:在非公平模式下,讀鎖可以“插隊”獲取鎖,即使有等待的寫線程。
  • 寫鎖需要獨占鎖:寫操作必須阻塞所有讀和寫,因此寫線程會一直等待,直到所有讀線程釋放讀鎖。

2. 等待隊列機制

AQS(AbstractQueuedSynchronizer)維護一個 FIFO 隊列

非公平模式下

  • 讀線程可以“插隊”獲取鎖(無需排隊)。
  • 寫線程只能按順序等待,直到?jīng)]有讀線程。

示例:

ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

// 線程 A: 讀線程
lock.readLock().lock();
try {
    while (true) {
        // 持續(xù)讀取(不釋放讀鎖)
    }
} finally {
    lock.readLock().unlock();
}

// 線程 B: 寫線程
lock.writeLock().lock(); // 被阻塞,永遠無法獲取寫鎖

3.2、實現(xiàn)原理

1. 寫鎖獲取流程

檢查當前是否有寫鎖(通過exclusiveCount判斷)。

檢查是否有讀鎖(通過sharedCount判斷)。

非公平模式下

  • 如果沒有寫鎖,且當前線程可以插隊(無需等待),則直接獲取寫鎖。
  • 如果有讀鎖或?qū)戞i,則將線程加入等待隊列。

公平模式下

  • 寫線程必須按順序等待,即使沒有讀鎖。

2. 寫鎖釋放流程

  1. 釋放寫鎖后,喚醒等待隊列中的線程。

非公平模式下

  • 新來的讀線程可能再次插隊獲取讀鎖。
  • 寫線程仍需等待所有讀線程釋放讀鎖。

3.3、避免寫鎖饑餓

1. 使用公平模式(Fair Mode)

  • 配置公平鎖new ReentrantReadWriteLock(true)

效果

  • 寫線程按順序獲取鎖,不會被讀線程插隊。
  • 優(yōu)點:避免寫鎖饑餓。
  • 缺點:性能略低(讀線程無法插隊)。

代碼示例:

ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); // 公平模式

void read() {
    lock.readLock().lock();
    try {
        // 讀取數(shù)據(jù)
    } finally {
        lock.readLock().unlock();
    }
}

void write() {
    lock.writeLock().lock();
    try {
        // 寫入數(shù)據(jù)
    } finally {
        lock.writeLock().unlock();
    }
}

公平模式下和非公平模式下:

2.限制讀鎖的持有時間

避免讀線程長期占用讀鎖

  • 在業(yè)務邏輯中控制讀鎖的持有時間。
  • 避免在讀鎖內(nèi)執(zhí)行長時間操作。

3. 使用StampedLock

在Java 8+,StampedLock提供更靈活的讀寫鎖策略

  • 支持樂觀讀鎖(不阻塞寫鎖)。
  • 支持寫鎖優(yōu)先級(避免讀鎖插隊)。

代碼示例:

StampedLock lock = new StampedLock();

void read() {
    long stamp = lock.tryOptimisticRead();
    if (lock.validate(stamp)) {
        // 樂觀讀取(不阻塞寫鎖)
    }
}

void write() {
    long stamp = lock.writeLock();
    try {
        // 寫入數(shù)據(jù)
    } finally {
        lock.unlockWrite(stamp);
    }
}

總結(jié)

通過合理選擇鎖策略,可以在高并發(fā)場景下平衡性能與公平性!

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • spring boot + jpa + kotlin入門實例詳解

    spring boot + jpa + kotlin入門實例詳解

    這篇文章主要介紹了spring boot + jpa + kotlin入門實例詳解 ,需要的朋友可以參考下
    2017-07-07
  • Java中實現(xiàn)OCR識別讀取圖片中的文字

    Java中實現(xiàn)OCR識別讀取圖片中的文字

    圖片內(nèi)容一般無法編輯,如果想要讀取圖片中的文本,我們需要用到OCR工具,本文將介紹如何在Java中實現(xiàn)OCR識別讀取圖片中的文字,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下
    2024-04-04
  • Java多線程模擬售票程序和線程安全問題

    Java多線程模擬售票程序和線程安全問題

    本篇文章給大家分享了Java多線程模擬售票程序和線程安全問題的相關(guān)知識點,對此有興趣的朋友可以參考學習下。
    2018-05-05
  • 詳解 Java 中 equals 和 == 的區(qū)別

    詳解 Java 中 equals 和 == 的區(qū)別

    這篇文章主要介紹了詳解 Java 中 equals 和 == 的區(qū)別的相關(guān)資料,equals 和 == 都是用來檢測兩個字符串是否相等,返回值也都是布爾型,但是兩者在內(nèi)部比較的處理中卻不盡相同需要的朋友可以參考下
    2017-03-03
  • Java中@DS+@Transactional注解切換數(shù)據(jù)源失效解決方案

    Java中@DS+@Transactional注解切換數(shù)據(jù)源失效解決方案

    本文主要介紹了@DS+@Transactional注解切換數(shù)據(jù)源失效解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • 詳解Java回環(huán)屏障CyclicBarrier

    詳解Java回環(huán)屏障CyclicBarrier

    這篇文章主要介紹了Java回環(huán)屏障CyclicBarrier的相關(guān)資料,幫助大家更好的理解和學習Java,感興趣的朋友可以了解下
    2020-09-09
  • java實現(xiàn)簡單的猜數(shù)字小游戲

    java實現(xiàn)簡單的猜數(shù)字小游戲

    這篇文章主要為大家詳細介紹了java實現(xiàn)簡單猜數(shù)字小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • Java使用遞歸法解決漢諾塔問題的代碼示例

    Java使用遞歸法解決漢諾塔問題的代碼示例

    這篇文章主要介紹了Java使用遞歸法解決漢諾塔問題的代碼示例,漢諾塔問題是使用遞歸解決問題的經(jīng)典范例,用到的算法非常簡單,需要的朋友可以參考下
    2016-04-04
  • Java設(shè)計模式之策略模式示例詳解

    Java設(shè)計模式之策略模式示例詳解

    策略模式屬于Java?23種設(shè)計模式中行為模式之一,該模式定義了一系列算法,并將每個算法封裝起來,使它們可以相互替換,且算法的變化不會影響使用算法的客戶。本文將通過示例詳細講解這一模式,需要的可以參考一下
    2022-03-03
  • Java8日期時間類LocalDateTime比較大小舉例

    Java8日期時間類LocalDateTime比較大小舉例

    LocalDate是Java?8中的日期類之一,它表示一個日期,下面這篇文章主要給大家介紹了關(guān)于Java8日期時間類LocalDateTime比較大小的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-05-05

最新評論

镇巴县| 中牟县| 榆中县| 阳高县| 都匀市| 澄迈县| 清丰县| 灵武市| 石首市| 沂南县| 康定县| 潼关县| 双辽市| 沙坪坝区| 长乐市| 綦江县| 蕲春县| 宁城县| 穆棱市| 佛坪县| 绥中县| 白沙| 邢台市| 东莞市| 河北省| 韩城市| 达拉特旗| 太仆寺旗| 马龙县| 巩义市| 辰溪县| 房山区| 慈利县| 札达县| 民县| 宜良县| 湄潭县| 嘉荫县| 梨树县| 渭南市| 临桂县|