首頁 Java java教程 JAVA之ReadWriteLock介面及其實作ReentrantReadWriteLock方法

JAVA之ReadWriteLock介面及其實作ReentrantReadWriteLock方法

Jun 30, 2017 am 10:32 AM
java readwritelock 實現

下面小編就為大家帶來一篇ReadWriteLock介面及其實作ReentrantReadWriteLock方法。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。一起跟著小編過來看看吧

Java並發包的locks包裡的鎖基本上已經介紹得差不多了,ReentrantLock重入鎖是個關鍵,在清楚的了解了同步器AQS的運行機制後,實際上再分析這些鎖就會顯得容易得多,這章節主講另外一個重要的鎖——ReentrantReadWriteLock讀寫鎖。

ReentrantLock是一個獨佔鎖,也就是說只能由一個執行緒取得鎖,但如果場景是執行緒只做讀取的操作呢?這樣ReentrantLock就不是很合適,讀的線程並不需要保證其線程的安全性,任何一個線程都能去獲取鎖,只有這樣才能盡可能地保證效能和效率。 ReentrantReadWriteLock就是這樣的一個鎖,在其內部分為讀鎖和寫鎖,可以有N個讀操作線程獲取到寫鎖,但是只能有1個寫操作線程獲取到寫鎖,那麼可以預見的是寫鎖是共享鎖(AQS中的共享模式),讀鎖是獨佔鎖(AQS中的獨佔模式)。首先來看讀寫鎖的介面類別:

public interface ReadWriteLock { 
  Lock readLock();  //获取读锁
  Lock writeLock();  //获取写锁
 }
登入後複製

可以看到ReadWriteLock介面只定義了兩個方法,取得讀鎖和取得寫鎖的方法。下面是ReadWriteLock的實作類別——ReentrantReadWriteLock。  

和ReentrantLock類似,ReentrantReadWriteLock在其內部也是透過一個內部類別Sync實現同步器AQS,同樣也是透過實現Sync實現公平鎖和非公平鎖,這一點的思路和ReentrantLock類似。在ReadWriteLock介面中所取得的讀鎖和寫鎖是怎麼實現的呢?

//ReentrantReadWriteLock
private final ReentrantReadWriteLock.ReadLock readerLock;
private final ReentrantReadWriteLock.WriteLock writerLock;
final Sync sync;
public ReentrantReadWriteLock(){
 this(false); //默认非公平锁
}
public ReentrantReadWriteLock(boolean fair) {
 sync = fair ? new FairSync() : new NonfairSync(); //锁类型(公平/非公平)
 readerLock = new ReadLock(this); //构造读锁
 writerLock = new WriteLock(this); //构造写锁
}
……
public ReentrantReadWriteLock.WriteLock writeLock0{return writerLock;}
public ReentrantReadWriteLock.ReadLock readLock0{return ReaderLock;}
登入後複製
//ReentrantReadWriteLock$ReadLock
public static class ReadLock implements Lock {
 protected ReadLock(ReentrantReadwritLock lock) {
  sync = lock.sync;  //最后还是通过Sync内部类实现锁
  }
 …… //它实现的是Lock接口,其余的实现可以和ReentrantLock作对比,获取锁、释放锁等等
}
登入後複製
//ReentrantReadWriteLock$WriteLock
public static class WriteLock implemnts Lock {
 protected WriteLock(ReentrantReadWriteLock lock) {
  sync = lock.sync;
  }
…… //它实现的是Lock接口,其余的实现可以和ReentrantLock作对比,获取锁、释放锁等等
}
登入後複製


上面是對ReentrantReadWriteLock做了一個大致的介紹,可以看到在其內部有好幾個內部類,實際上讀寫鎖內有兩個鎖— —ReadLock、WriteLock,這兩個鎖都是實現自Lock接口,可以和ReentrantLock對比,而這兩個鎖的內部實現則是透過Sync,也就是同步器AQS實現的,這也可以和ReentrantLock中的Sync對比。
  回顧AQS,其內部有兩個重要的資料結構-一個是同步佇列、一個則是同步狀態,這個同步狀態應用在讀寫鎖定中也就是讀寫狀態,但AQS中只有一個state整數來表示同步狀態,讀寫鎖定中則有讀取、寫入兩個同步狀態需要記錄。所以,讀寫鎖將AQS中的state整型做了一下處理,它是一個int型變數一共4個位元組32位,那麼可以讀寫狀態就可以各佔16位元-高16位表示讀,低16位表示寫。

  

現在有一個疑問如果state的值位元5,二進位為(00000000000000000000000000000101),如何快速確定讀取和寫入各自的狀態呢?這就要用到位移運算了。計算方式為:寫入狀態state & 0x0000FFFF,讀取狀態state >>> 16。寫入狀態增加1等於state + 1,讀取狀態增加1等於state + (1 << 16)。有關移位元運算可以參考《<<、>>、>>>移位運算》。

寫入鎖的取得與釋放

根據我們先前的經驗可以得知:AQS已經將取得鎖的演算法骨架搭好了,只需子類別實現tryAcquire(獨佔鎖),故我們只需查看tryAcquire。

//ReentrantReadWriteLock$Sync
protected final boolean tryAcquire(int acquires) {
 Thread current = Thread.currentThread;
 int c = getState(); //获取state状态
 int w = exclusiveCount(c); //获取写状态,即 state & 0x00001111
 if (c != 0) { //存在同步状态(读或写),作下一步判断
  if (w == 0 || current != getExclusiveOwnerThread())  //写状态为0,但同步状态不为0表示有读状态,此时获取锁失败,或者当前已经有其他写线程获取了锁此时也获取锁失败
   return false;
  if (w + exclusiveCount(acquire) > MAX_COUNT) //锁重入是否超过限制
   throw new Error(“Maxium lock count exceeded”);
  setState(c + acquire); //记录锁状态
  return true;
  }
  if (writerShouldBlock() || !compareAndSetState(c, c + acquires))
   return false;  //writerShouldBlock对于非公平锁总是返回false,对于公平锁则判断同步队列中是否有前驱节点
  setExclusiveOwnerThread(current);
  return true;
}
登入後複製

上面是寫鎖的狀態獲取,不好理解的是writerShouldBlock方法,此方法上面有描述,非公平鎖直接回傳false,而對於公平鎖則是呼叫hasQueuedPredecessors方法如下:

 //ReentrantReadWriteLock$FairSync
 final boolean writerShouldBlock() {
  return hasQueuedPredecessors();
 }
登入後複製

原因是為什麼?這就要回到非公平鎖和公平鎖的區別上來了,簡單回顧一下,詳情可參考《5.Lock介面及其實作ReentrantLock》。對於非公平鎖,每次線程獲取鎖時首先會強行進行鎖獲取操作而不管同步隊列中是否有線程,當獲取不到時才會將線程構造至隊尾;對於公平鎖來講,只要同步隊列中存在線程,就不會去獲取鎖,而是將線程構造加到隊尾。所以重新回到寫入狀態的取得上,tryAcquire方法裡,前面發現沒有線程持有鎖,但是此時會根據鎖的不同做相應操作,對於非公平鎖——搶鎖,對公平鎖——同步隊列中有線程,不搶鎖,添加至隊尾排隊。

寫鎖的釋放與ReentrantLock的釋放過程基本類似,畢竟都是獨佔鎖,每次釋放減少寫的狀態,直到減小到0就表示寫鎖已經完全釋放。

讀取鎖定的取得與釋放

同理,根據我們之前的經驗可以得知:AQS已經將獲取鎖的演算法骨架搭好了,只需子類別實作tryAcquireShared(共享鎖),故我們只需查看tryAcquireShared。我們知道共享模式下的鎖,它能夠被多個線程同時獲取,現在問題來了,T1線程獲取了鎖,同步狀態state=1,此時T2也獲取了鎖,state=2,接著T1線程重入state=3,也就是說讀狀態是所有執行緒讀鎖次數的總和,而每個執行緒各自取得讀鎖的次數只能選擇保存在ThreadLock中,由執行緒自身維護,所以在這個地方要做一些複雜處理,原始碼有點長,但複雜就在於每個執行緒保存自身取得讀鎖的次數,具體參考源碼的tryAcquireShared,仔細閱讀並結合上面對寫鎖獲取的分析不難讀懂。

讀鎖的釋放值得注意的地方在於自身維護的獲取鎖定的次數,以及透過移位操作減少狀態state – (1 << 16)。

以上是JAVA之ReadWriteLock介面及其實作ReentrantReadWriteLock方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1659
14
CakePHP 教程
1415
52
Laravel 教程
1310
25
PHP教程
1258
29
C# 教程
1232
24
突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHP的影響:網絡開發及以後 PHP的影響:網絡開發及以後 Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

See all articles