1. 程式人生 > >ReentrantReadWriterLock原始碼(state設計、讀寫鎖、共享鎖、獨佔鎖及鎖降級)

ReentrantReadWriterLock原始碼(state設計、讀寫鎖、共享鎖、獨佔鎖及鎖降級)

#### ReentrantReadWriterLock 讀寫鎖類圖(截圖來源https://blog.csdn.net/wangbo199308/article/details/108688148) ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201217222326157.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzg0MzEwNA==,size_16,color_FFFFFF,t_70) ###### state的設計 讀寫鎖將變數state切分成兩個部分,高16位表示讀,低16位表示寫 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201217223627709.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzg0MzEwNA==,size_16,color_FFFFFF,t_70) 原始碼中將4位元組(32位)的int資料型別state,通過SHARED_SHIFT(16)劃分讀和寫; 每次讀鎖增加的單元,SHARED_UNIT = (1 << SHARED_SHIFT) 也即0x00010000,即每次讀鎖增加從17位開始加1 讀寫鎖最大數量:MAX_COUNT = (1 << SHARED_SHIFT) - 1,16位最大值 寫鎖的掩碼:EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1, 即求寫鎖數量,將state和此掩碼做與運算,將高16位抹去 計算讀鎖數量邏輯:c >>> SHARED_SHIFT,取高16位 計算寫鎖數量邏輯:c & EXCLUSIVE_MASK,將state和此掩碼做與運算,將高16位抹去 ``` public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { abstract static class Sync extends AbstractQueuedSynchronizer { //16位劃分讀和寫 static final int SHARED_SHIFT = 16; static final int SHARED_UNIT = (1 << SHARED_SHIFT); static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; static int sharedCount(int c) { return c >>> SHARED_SHIFT; } static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; } } } ``` ###### 讀鎖 讀鎖上鎖的呼叫鏈:ReentrantReadWriteLock$ReadLock#lock() -->AbstractQueuedSynchronizer#acquireShared() -->ReentrantReadWriteLock$Sync#tryAcquireShared() 當前寫鎖數量為0或獨佔鎖持有者就是當前執行緒才進行讀鎖邏輯 讀鎖數量通過CAS加1 之後邏輯是將讀鎖執行緒放入ThreadLocal中,記錄各自鎖數量 ``` public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { public static class ReadLock implements Lock, java.io.Serializable { public void lock() { sync.acquireShared(1); } } } ``` ``` public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); } } ``` ``` public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { abstract static class Sync extends AbstractQueuedSynchronizer { protected final int tryAcquireShared(int unused) { Thread current = Thread.currentThread(); int c = getState(); // 同時滿足寫鎖數量不為0,且獨佔鎖不是當前執行緒,走doAcquireShared邏輯 if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return -1; // 取高16位讀鎖數量 int r = sharedCount(c); if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) { // ThreadLocal存放鎖資訊 if (r == 0) { firstReader = current; firstReaderHoldCount = 1; } else if (firstReader == current) { firstReaderHoldCount++; } else { 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); } } } ``` 在讀鎖獲取鎖過程,寫鎖不為0且佔有寫鎖的不是當前執行緒,返回-1,走同步器doAcquireShared方法,等待寫鎖釋放; 前置節點是head節點時,嘗試獲取共享鎖 ``` private void doAcquireShared(int arg) { // 佇列加入的node是共享模式 final Node node = addWaiter(Node.SHARED); boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head) { //前置節點是head節點時,嘗試獲取共享鎖 int r = tryAcquireShared(arg); if (r >= 0) { setHeadAndPropagate(node, r); p.next = null; // help GC if (interrupted) selfInterrupt(); failed = false; return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } } ``` ###### 寫鎖 1. 讀鎖不為0,但寫鎖為0,獲取鎖失敗;讀鎖不為0,寫鎖也不為0,但獨佔鎖不是當前執行緒,獲取鎖失敗 2. 如果鎖數量已到最大,獲取失敗 3. 否則獲取寫鎖,更新state ``` public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { abstract static class Sync extends AbstractQueuedSynchronizer { protected final boolean tryAcquire(int acquires) { Thread current = Thread.currentThread(); 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; } } } ``` ###### 共享鎖和獨佔鎖 讀鎖是共享鎖,當執行緒1獲得讀鎖時,並不會排斥執行緒2去獲取讀鎖,而是在ThreadLocal中儲存每個鎖數量 ``` abstract static class Sync extends AbstractQueuedSynchronizer { static final class HoldCounter { int count = 0; // Use id, not reference, to avoid garbage retention final long tid = getThreadId(Thread.currentThread()); } static final class ThreadLocalHoldCounter extends Thr