public class LockDemo { ArrayList<Integer> arrayList = new ArrayList<>();//定義一個集合 // 定義讀鎖 ReentrantReadWriteLock.ReadLock readLock = new ReentrantReadWriteLock(true).readLock(); // 定義寫鎖 ReentrantReadWriteLock.WriteLock writeLock = new ReentrantReadWriteLock(true).writeLock(); public void addEle(Integer ele) { writeLock.lock(); // 獲取寫鎖 arrayList.add(ele); writeLock.unlock(); // 釋放寫鎖 } public Integer getEle(Integer index) { try{ readLock.lock(); // 獲取讀鎖 Integer res = arrayList.get(index); return res; } finally{ readLock.unlock();// 釋放讀鎖 } } }
ReentrantReadWriteLock中的lock方法java
public void lock() { sync.acquire(1); }
AbstractQueuedSynchronizer中的acquire方法安全
public final void acquire(int arg) { // 獲取鎖失敗則進入阻塞隊列 if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))**,中的acquireQueued方法和addWaiter方法在前面的文章中都已經進行了詳細的解釋說明。**
ide
ReentrantReadWriteLock中的tryAcquire方法源碼分析
protected final boolean tryAcquire(int acquires) { // 獲取當前線程 Thread current = Thread.currentThread(); // 獲取狀態 int c = getState(); // 計算寫線程數量就是獨佔鎖的可從入數量 int w = exclusiveCount(c); // 當前同步狀態state != 0,說明已經有其餘線程獲取了讀鎖或寫鎖 if (c != 0) { // 當前state不爲0,此時:若是寫鎖狀態爲0說明讀鎖此時被佔用返回false; // 若是寫鎖狀態不爲0且寫鎖沒有被當前線程持有返回false if (w == 0 || current != getExclusiveOwnerThread()) return false; // 判斷同一線程獲取寫鎖是否超過最大次數(65535),支持可重入 if (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error("Maximum lock count exceeded"); //更新狀態 //此時當前線程已持有寫鎖,如今是重入,因此只須要修改鎖的數量便可 setState(c + acquires); return true; } //到這裏說明此時c=0,讀鎖和寫鎖都沒有被獲取 //writerShouldBlock表示是否阻塞 if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) return false; // 設置鎖爲當前線程全部 setExclusiveOwnerThread(current); return true; } static final class FairSync extends Sync { // 寫鎖是否應該被阻塞 final boolean writerShouldBlock() { return hasQueuedPredecessors(); } }
寫鎖的獲取過程以下:ui
ReentrantReadWriteLock中的unlock方法線程
public void unlock() { sync.release(1); }
AbstractQueuedSynchronizer中的release方法3d
public final boolean release(int arg) { // 若是返回true 那麼釋放成功了 if (tryRelease(arg)) { Node h = head; // 若是頭部不爲空,而且頭節點的waitStatus是喚醒狀態那麼喚醒後繼線程 if (h != null && h.waitStatus != 0) // 喚醒後繼線程 unparkSuccessor(h); return true; } return false; }
ReentrantReadWriteLock中tryRelease方法code
protected final boolean tryRelease(int releases) { // 若鎖的持有者不是當前線程,拋出異常 if (!isHeldExclusively()) // 非法的監控器異常 throw new IllegalMonitorStateException(); // 計算寫鎖的新線程數 int nextc = getState() - releases; // 若是獨佔模式重入數爲0了,說明獨佔模式被釋放 boolean free = exclusiveCount(nextc) == 0; if (free) // 設置獨佔線程爲空 setExclusiveOwnerThread(null); // 設置寫鎖的新線程數 // 無論獨佔模式是否被釋放,更新獨佔重入數 setState(nextc); return free; } protected final boolean isHeldExclusively() { // 若當前線程是當前鎖的持有線程那麼返回true return getExclusiveOwnerThread() == Thread.currentThread(); }
寫鎖的釋放過程:blog
private volatile int state;
int 類型佔有 4個字節一個字節8位,因此 state 一個 32 位,高 16 位 表明讀鎖 低 16 位表明 寫鎖。隊列
// 0x0000FFFF 16 進制 // 1111111111111111 2 進制 // 65535 10 進制 static final int SHARED_SHIFT = 16; static final int SHARED_UNIT = (1 << SHARED_SHIFT); // 65536 static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; //65535 // 1111111111111111 static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; // 65535 // 1111111111111111
若是此時同步狀態位 c 那麼獲取寫狀態 c & EXCLUSIVE_MASK
若是此時同步狀態位 c 那麼獲取讀狀態 c >>>16 無符號補0,右移16位
*以上即是ReentrantReadWriteLock中寫鎖的分析,下一篇文章將是***Condition**的分析,若有錯誤之處,幫忙指出及時更正,謝謝,若是喜歡謝謝點贊加收藏加轉發(轉發註明出處謝謝!!!)