1. 程式人生 > >搞定ReentrantReadWriteLock 幾道小小數學題就夠了

搞定ReentrantReadWriteLock 幾道小小數學題就夠了

| **好看請贊,養成習慣** > - 你有一個思想,我有一個思想,我們交換後,一個人就有兩個思想 > > - If you can NOT explain it simply, you do NOT understand it well enough 現陸續將Demo程式碼和技術文章整理在一起 [Github實踐精選](https://github.com/FraserYu/learnings) ,方便大家閱讀檢視,本文同樣收錄在此,覺得不錯,還請Star ![](https://img2020.cnblogs.com/other/1583165/202006/1583165-20200624084554199-997994831.png) ## 前言 - 文章 [Java AQS佇列同步器以及ReentrantLock的應用](https://dayarch.top/p/java-aqs-and-reentrantlock.html) 介紹了AQS**獨佔式獲取同步狀態**的實現,並以 ReentrantLock 為例說明其是如何自定義同步器實現互斥鎖的 - 文章 [Java AQS共享式獲取同步狀態及Semaphore的應用分析](https://dayarch.top/p/java-aqs-acquireshared-and-semaphore.html) 介紹 AQS **共享式獲取同步狀態**的實現,並說明了 Semaphore 是如何自定義同步器實現簡單限流作用的 有了以上兩篇文章的鋪墊,來理解本文要介紹的既有獨佔式,又有共享式獲取同步狀態的 `ReadWriteLock`,就非常輕鬆了 ![](https://img2020.cnblogs.com/other/1583165/202006/1583165-20200624084554650-1070257189.png) ## ReadWriteLock `ReadWriteLock` 直譯過來為【讀寫鎖】。現實中,讀多寫少的業務場景是非常普遍的,比如應用快取 > 一個執行緒將資料寫入快取,其他執行緒可以直接讀取快取中的資料,提高資料查詢效率 之前提到的互斥鎖都是排他鎖,也就是說同一時刻只允許一個執行緒進行訪問,當面對可共享讀的業務場景,互斥鎖顯然是比較低效的一種處理方式。為了提高效率,讀寫鎖模型就誕生了 效率提升是一方面,但併發程式設計更重要的是在保證準確性的前提下提高效率 > 一個寫執行緒改變了快取中的值,其他讀執行緒一定是可以 **“感知”** 到的,否則可能導致查詢到的值不準確 所以關於讀寫鎖模型就了下面這 3 條規定: 1. 允許多個執行緒同時讀共享變數 2. 只允許一個執行緒寫共享變數 3. 如果寫執行緒正在執行寫操作,此時則禁止其他讀執行緒讀共享變數 `ReadWriteLock` 是一個介面,其內部只有兩個方法: ```java public interface ReadWriteLock { // 返回用於讀的鎖 Lock readLock(); // 返回用於寫的鎖 Lock writeLock(); } ``` 所以要了解整個讀/寫鎖的整個應用過程,需要從它的實現類 `ReentrantReadWriteLock` 說起 ### ReentrantReadWriteLock 類結構 直接對比ReentrantReadWriteLock 與 ReentrantLock的類結構 ![](https://img2020.cnblogs.com/other/1583165/202006/1583165-20200624084555158-1388166534.png) 他們又很相似吧,根據類名稱以及類結構,按照咱們前序文章的分析,你也就能看出 ReentrantReadWriteLock 的基本特性: ![](https://img2020.cnblogs.com/other/1583165/202006/1583165-20200624084555709-4292919.png) 其中黃顏色標記的的 **鎖降級** 是看不出來的, 這裡先有個印象,下面會單獨說明 另外,不知道你是否還記得,[Java AQS佇列同步器以及ReentrantLock的應用](https://dayarch.top/p/java-aqs-and-reentrantlock.html) 說過,Lock 和 AQS 同步器是一種組合形式的存在,既然這裡是讀/寫兩種鎖,他們的組合模式也就分成了兩種: 1. 讀鎖與自定義同步器的聚合 2. 寫鎖與自定義同步器的聚合 ```java public ReentrantReadWriteLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); } ``` ![](https://img2020.cnblogs.com/other/1583165/202006/1583165-20200624084556162-374219872.png) 這裡只是提醒大家,模式沒有變,不要被讀/寫兩種鎖迷惑 #### 基本示例 說了這麼多,如果你忘了前序知識,整體理解感覺應該是有斷檔的,所以先來看個示例(模擬使用快取)讓大家對 ReentrantReadWriteLock 有個直觀的使用印象 ```java public class ReentrantReadWriteLockCache { // 定義一個非執行緒安全的 HashMap 用於快取物件 st