bilibili-Java併發學習筆記16 AQS 之 ReentrantReadWriteLock
基於 java 1.8.0
P48_可重入讀寫鎖底層源碼分析及思想探究
// ReadWriteLock 使用示例
package new_package.thread.p45;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.IntStream;
public class ReadWriteLockTest {
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void method1() {
try {
readWriteLock.readLock().lock();
System.out.println("method1");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
public void method2() {
try {
readWriteLock.writeLock().lock();
System.out.println("method2");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
public static void main(String[] args) {
ReadWriteLockTest demo = new ReadWriteLockTest();
IntStream.range(0, 10).forEach(k -> new Thread(() -> {
demo.method2();
}).start());
}
}
- 公平鎖與非公平鎖
類似 ReentrantLock ,在構造器中指定是否爲公平鎖,默認非公平模式;
// 默認非公平模式
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 指定爲公平模式
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
/** Inner class providing readlock */
private final ReentrantReadWriteLock.ReadLock readerLock;
/** Inner class providing writelock */
private final ReentrantReadWriteLock.WriteLock writerLock;
/** Performs all synchronization mechanics */
final Sync sync;
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
// 關於同步器
/**
* ReentrantReadWriteLock 的內部類,同步器的實現
* 子類有公平版本和非公平版本
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
///
}
/**
* 非公平版本的 Sync
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; // writers can always barge
}
final boolean readerShouldBlock() {
/* As a heuristic to avoid indefinite writer starvation,
* block if the thread that momentarily appears to be head
* of queue, if one exists, is a waiting writer. This is
* only a probabilistic effect since a new reader will not
* block if there is a waiting writer behind other enabled
* readers that have not yet drained from the queue.
*/
return apparentlyFirstQueuedIsExclusive();
}
}
/**
* 公平版本的 Sync
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
// 關於讀寫鎖實現
/**
* ReentrantReadWriteLock 的內部類
* The lock returned by method {@link ReentrantReadWriteLock#readLock}.
*/
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
/**
* Constructor for use by subclasses
*
* @param lock the outer lock object
* @throws NullPointerException if the lock is null
*/
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
// ...
}
/**
* ReentrantReadWriteLock 的內部類
* The lock returned by method {@link ReentrantReadWriteLock#writeLock}.
*/
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
/**
* Constructor for use by subclasses
*
* @param lock the outer lock object
* @throws NullPointerException if the lock is null
*/
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
// ...
}
- 讀鎖的上鎖
readWriteLock.readLock().lock();
// 實現
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
// 嘗試獲取共享鎖
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
* 1. 如果另一個線程持有寫鎖,則失敗。
* 2. 否則,此線程符合 lock wrt state 的條件,
* 因此詢問它是否應該因爲隊列策略而阻塞。
* 如果沒有,嘗試通過大小寫狀態和更新計數來授予。
* 注意,step不檢查可重入獲取,它被推遲到完整版本,
* 以避免在更典型的不可重入情況下檢查保留計數。
* 3. 如果步驟2失敗是因爲線程明顯不合格、CAS失敗或計數飽和,
* 則使用完整的重試循環鏈到版本。
*/
Thread current = Thread.currentThread();
int c = getState();
// 校驗是否有獨佔鎖
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
// 有獨佔鎖直接返回,獲取共享鎖失敗
return -1;
// 獲取共享鎖已被佔有幾次了
int r = sharedCount(c);
//
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
// 獲取到讀鎖
if (r == 0) {
// 本線程爲第一個獲取到此共享鎖的線程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
// 共享鎖的佔有數不爲0
// 第一個獲取到此共享鎖的線程是本線程
firstReaderHoldCount++;
} else {
// 共享鎖的佔有數不爲0 ,且 firstReader 不是當前線程
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
// int 類型佔 4 byte,佔 32 bit (一半就是 16 bit)
static final int SHARED_SHIFT = 16;
// 1 左移 16 位 :00000000 00000001 00000000 00000000
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
// (1 左移 16 位) -1 :00000000 00000000 11111111 11111111
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/**
* 返回以count表示的共享保留數
* state 無邏輯右移 16 位,即 state 的高16位
*/
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/**
* 返回以count表示的獨佔保留數
* state & 00000000 00000000 11111111 11111111 即:state 的低16位
*/
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
// << 表示左移,不分正負數,低位補0;
// >> 表示右移,如果該數爲正,則高位補0,若爲負數,則高位補1;
// >>> 表示無符號右移,也叫邏輯右移,即無論該數爲正負,都是高位補0
// Fair version of Sync
final boolean readerShouldBlock() {
// 等待隊列中是否還有前置節點
return hasQueuedPredecessors();
}
// Nonfair version of Sync
final boolean readerShouldBlock() {
//
return apparentlyFirstQueuedIsExclusive();
}
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
- 寫鎖的上鎖
readWriteLock.writeLock().lock();
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
// 嘗試獲取獨佔鎖
// 若獲取失敗,則加入等待隊列
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// Sync in ReentrantReadWriteLock 的實現
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
* 1. 如果讀計數非零或寫入計數非零且所有者是不同的線程,則失敗。
* 2. 如果計數飽和,則失敗。(只有當count已非零時纔會發生這種情況。)
* 3. 否則,如果這個線程是可重入的獲取或隊列策略允許的話,它就有資格被鎖定。如果是,請更新狀態並設置所有者。
*/
Thread current = Thread.currentThread();
// state 的狀態
int c = getState();
// 獨佔鎖數量
int w = exclusiveCount(c);
//
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
// 有共享鎖佔有
// 當前獨佔鎖不是當前線程佔有的
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
P49_可重入讀寫鎖的共享鎖釋放源碼解析
- 讀鎖的釋放
readWriteLock.readLock().unlock();
public void unlock() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
// Releasing the read lock has no effect on readers,
// but it may allow waiting writers to proceed if
// both read and write locks are now free.
return nextc == 0;
}
}
- 寫鎖的釋放
readWriteLock.writeLock().unlock();
public void unlock() {
sync.release(1);
}
// AQS
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}