1.3 EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock
上一篇說到了WriterPreferenceReadWriteLock,這一篇說一下ReentrantWriterPreferenceReadWriteLock。
顧名思義,該類實現的是可重入的的WriterPreferenceReadWriteLock。允許readers和writers在各自線程裡反復獲得讀或寫的鎖。這種方法主要用在
該類是WriterPreferenceReadWriteLock的子類,與父類大體流程一致,但是startWrite,startRead ,allowReader ,endRead和endWrite被重寫,下面逐一解釋。
先看看新添加的成員變量
Java代碼
- /**在activeWriter線程裡,有多少次write鎖的控制權被獲取**/
- protected long writeHolds_ = 0;
- /**存放的每個reader線程共申請獲得多少次讀控制,key值是thread對象,value是次數**/
- protected HashMap readers_ = new HashMap();
- /*一個int的常量緩存*/
- protected static final Integer IONE = new Integer(1);
再來看看Reader部分的重寫函數
Java代碼
- protected boolean allowReader() {
- //與父類的變化在於,activeWriter_ == Thread.currentThread(),
- //也就是說當本線程已經獲得寫控制的時候,返回true
- return (activeWriter_ == null && waitingWriters_ == 0) ||
- activeWriter_ == Thread.currentThread();
- }
- protected synchronized boolean startRead() {
- Thread t = Thread.currentThread();
- //查看本線程是否已經獲得讀控制
- Object c = readers_.get(t);
- if (c != null) { // already held -- just increment hold count
- //計數+1
- readers_.put(t, new Integer(((Integer)(c)).intValue()+1));
- ++activeReaders_;
- return true;
- }
- //調用allowReader
- else if (allowReader()) {
- //將本線程獲鎖次數紀錄在readers_這個map裡
- readers_.put(t, IONE);
- ++activeReaders_;
- return true;
- }
- else
- return false;
- }
- protected synchronized Signaller endRead() {
- Thread t = Thread.currentThread();
- Object c = readers_.get(t);
- if (c == null)
- throw new IllegalStateException();
- --activeReaders_;
- if (c != IONE) { // 多於一個讀線程有控制權,more than one hold; 計數遞減
- int h = ((Integer)(c)).intValue()-1;
- Integer ih = (h == 1)? IONE : new Integer(h);
- readers_.put(t, ih);
- return null;
- }
- else {
- readers_.remove(t);
- if (writeHolds_ > 0) // 本線程還有寫鎖在占用控制權
- return null;
- //其余與父類實現一樣
- else if (activeReaders_ == 0 && waitingWriters_ > 0)
- return writerLock_;
- else
- return null;
- }
- }
Reader部分相對於父類的變化在於
* 每個reader試圖競爭控制權時,都會將本線程句柄與activeWriter進行比較,相同則認為是可以重入。
* 每個reader線程都在readers_的map裡有一個計數器,判斷當前有多少次獲得reader鎖權,釋放的時候,只有當計數器為0時才通知其他寫線程結束wait。
接著看看Writer部分的重寫函數
Java代碼
- protected synchronized boolean startWrite() {
- if (activeWriter_ == Thread.currentThread()) { // 反復重入
- ++writeHolds_;
- return true;
- }
- else if (writeHolds_ == 0) {
- //如果沒有人在讀(activeReaders_==0)和,或者在讀的線程和本線程一樣,並且readers裡沒有其他線程
- if (activeReaders_ == 0 ||
- (readers_.size() == 1 &&
- readers_.get(Thread.currentThread()) != null)) {
- //如果本線程在讀中,則也可以進入writeLock
- activeWriter_ = Thread.currentThread();
- writeHolds_ = 1;
- return true;
- }
- else
- return false;
- }
- else
- return false;
- }
- protected synchronized Signaller endWrite() {
- --writeHolds_;
- if (writeHolds_ > 0)
- //這是主要與父類不一樣的地方,寫鎖計數標示仍然有寫鎖沒有被釋放
- return null;
- else {
- //與父類一致
- activeWriter_ = null;
- if (waitingReaders_ > 0 && allowReader())
- return readerLock_;
- else if (waitingWriters_ > 0)
- return writerLock_;
- else
- return null;
- }
- }
Writer主要與父類不同的地方是
* 通過writeHolds來記錄本線程獲得鎖的次數,以便在release時正確調用通知機制
* 通過當前線程和activeWriter線程比較來實現重入
1.3 EDU.oswego.cs.dl.util.concurrent.ReaderPreferenceReadWriteLock
ReaderPreferenceReadWriteLock類和父類唯一不同就是allowReader方法
Java代碼
- protected boolean allowReader() {
- //只要沒有寫,就允許讀
- return activeWriter_ == null;
- }
這個類在大多數場景下都不太實用,多數人主要還是使用writer優先鎖。