JAVA併發之Lock(下——實現)

在上一節中,描述了Lock包的核心基礎–AQS,本節將講述其具體實現:ReentrantLock,ReentrantReadWriteLock。在這之前先說一下必要定義。
可重入鎖:已在syn章節提及過,此處詳細描述。某個線程獲取到鎖之後,在未釋放鎖之前的時間內,當需要獲取鎖時不需要獲取鎖的操作,可直接拿到資源。
公平鎖:通俗的說,就是先等待的線程先獲得鎖。
非公平鎖:與公平鎖相反,每次需要獲取鎖時大家一起競爭,並不是先到先得。鎖。

一、ReentrantLock

ReentrantLock是可重入鎖,獨佔鎖,實現Lock接口,內部實現了公平鎖與非公平鎖兩種鎖形式,默認使用非公平鎖。

一、屬性


 private final Sync sync;

該類有屬性Sync,用final修飾即初始化之後不可更改,Sync是AQS的一個子類,有兩個子類NonfairSync與FairSync,分別用於實現非公平鎖與公平鎖。

二、靜態內部類
接下來是靜態內部類,這裏使用靜態內部類便是爲了讓這些類中的方法都只讓ReentrantLock使用。


1.Sync
該類是AQS的子類,重寫了一些方法(AQS需要實現,公平鎖與非公平鎖通用),是NonfairSync與FairSync的父類。
接下如acquire(),tryAcquire(),release()等屬於AQS類的重要方法,在上一篇描述AQS的blog中已經詳細闡述,此處不再闡述。

 abstract static class Sync extends AbstractQueuedSynchronizer {
        abstract void lock();
        //不公平獲取鎖
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            } else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        //嘗試釋放鎖
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
        //是否擁有當前鎖
        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
        //獲取一個條件隊列
        final ConditionObject newCondition() {
            return new ConditionObject();
        }
         //獲取佔有鎖的線程
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
         //獲取該線程佔有多少資源
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }
        //資源是否被搶佔
        final boolean isLocked() {
            return getState() != 0;
        }
    }

上述代碼實現都比較簡單,根據註釋就能瞭解,不再分析。
2.NonfairSync
該類是Sync的實現類,是不公平鎖的實現。在ReentrantLock中使用的

static final class NonfairSync extends Sync {
    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

上述代碼有兩方法:
lock():獲取獨佔鎖,若未獲取則將線程阻塞等待。實現較簡單:使用CAS將state從0置爲1,若成功則代表獲取資源成功;若失敗則調用acquire()進行操作。
tryAcquire():獲取鎖,此處是直接調用父類Sync的nonfairTryAcquire方法。
疑問:nonfairTryAcquire()方法是不公平的獲取鎖,爲什麼要置於父類中,而不是子類NonfairSync中?
解答:通過跟蹤源碼,發現nonfairTryAcquire方法除了此處還有一處調用,在ReentrantLock對外提供的tryLock()方法中,用於立刻獲取獨佔鎖。故若將該方法放入子類NonfairSync中,則公平鎖無法提供此功能。而對於我們來說,即使我們實現的是公平鎖,在某些時刻也需要此功能。
3.FairSync
該類是Sync的實現類,是公平鎖的實現。在ReentrantLock中使用的

static final class FairSync extends Sync {
    final void lock() {
        acquire(1);
    }
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
       }else if (current == getExclusiveOwnerThread()) {
           int nextc = c + acquires;
           if (nextc < 0)
              throw new Error("Maximum lock count exceeded");
           setState(nextc);
           return true;
        }
        return false;
    }
}

上述代碼有兩方法:
lock():獲取獨佔鎖,直接調用acquire()進行操作。
tryAcquire():獲取鎖。

4.總結
通過上述公平鎖與非公平鎖的實現,其區別在於:

  1. lock():獲取獨佔鎖,公平鎖時直接調用acquire(1),將該線程放入隊尾,等待獲取;而非公平鎖則是先直接獲取鎖(無論CLH隊列中是否有其他線程在等待),失敗纔會將該線程放入隊尾。
  2. tryAcquire():嘗試獲取鎖,其實此方法只是獲取鎖過程中的一部分。其區別在於可以獲取鎖時,公平鎖的處理是!hasQueuedPredecessors() &&compareAndSetState(0, acquires),需要在隊列前面沒有其他等待線程纔會嘗試獲取鎖;而非公平鎖的處理是compareAndSetState(0, acquires),無論是否有其他線程,直接嘗試獲取鎖。

三、構造器
ReentrantLock對外提供兩個構造器:

public ReentrantLock() {
    sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
  1. ReentrantLock(),默認構造器,默認使用非公平鎖,故上文中描述該類默認使用非公平鎖
  2. ReentrantLock(boolean fair),帶參構造器,傳入true則是公平鎖,false是非公平鎖

四、對外提供方法
ReentrantLock提供了一系列方法,都是基於AQS以及上述Sync系列靜態內部類實現,實現原理較簡單,作用見註釋,不一一詳述。

//獲取鎖,若未獲取則將線程阻塞等待
public void lock() {
    sync.lock();
}
//獲取鎖。若未獲取則將線程阻塞等待,直到獲取鎖。如果有中斷請求就會產生中斷異常
public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}
//立刻嘗試獲取鎖
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}
//立刻嘗試在指定時間內獲取鎖,直接調用AQS中方法
public boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
//釋放鎖
public void unlock() {
    sync.release(1);
}
//獲取新的等待隊列
public Condition newCondition() {
    return sync.newCondition();
}
//獲取當先線程佔有資源數
public int getHoldCount() {
    return sync.getHoldCount();
}
//是否是當前線程佔有鎖
public boolean isHeldByCurrentThread() {
    return sync.isHeldExclusively();
}
//鎖是否被持有
public boolean isLocked() {
    return sync.isLocked();
}
//是否是公平鎖
public final boolean isFair() {
    return sync instanceof FairSync;
}
//獲取持有鎖的線程
protected Thread getOwner() {
    return sync.getOwner();
}
//是否有線程等待獲取鎖
 public final boolean hasQueuedThreads() {
    return sync.hasQueuedThreads();
}
//CLH隊列長度
public final int getQueueLength() {
    return sync.getQueueLength();
}
//獲取所有正在等待獲取鎖的線程,返回是list<Thread>
protected Collection<Thread> getQueuedThreads() {
    return sync.getQueuedThreads();
}
//等待隊列中是否有等待線程
public boolean hasWaiters(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
        throw new IllegalArgumentException("not owner");
    return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//等待隊列中的線程數
public int getWaitQueueLength(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
        throw new IllegalArgumentException("not owner");
    return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//獲取所有等待隊列中的線程,返回是list<Thread>
protected Collection<Thread> getWaitingThreads(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
        throw new IllegalArgumentException("not owner");
    return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}

一、ReentrantReadWriteLock

ReentrantReadWriteLock是可重入鎖。裏面有兩把鎖,讀鎖與寫鎖,其中讀鎖採用共享鎖,寫鎖採用獨佔鎖。不能同時存在讀鎖與寫鎖。內部實現了公平鎖與非公平鎖兩種鎖形式,默認使用非公平鎖。
寫線程雖然一次只有一個訪問數據,但讀線程可以同時讀取,而在實際中,讀取往往都是大量的,寫入是偶爾的,讀-寫鎖利用了這一點。從理論上講,與互斥鎖相比,使用讀-寫鎖所允許的併發性增強將帶來更大的性能提高。在實踐中,只有在多處理器上並且只在訪問模式適用於共享數據時,才能完全實現併發性增強。
讀寫鎖不能同時存在。

一、屬性


private final ReentrantReadWriteLock.ReadLock readerLock;
private final ReentrantReadWriteLock.WriteLock writerLock;
final Sync sync;

該類有屬性Sync,readerLock,writerLock,均用final修飾即初始化之後不可更改,Sync是AQS的一個子類,有兩個子類NonfairSync與FairSync,分別用於實現非公平鎖與公平鎖。readerLock爲讀鎖,writerLock爲寫鎖

二、靜態內部類
接下來是靜態內部類,這裏使用靜態內部類便是爲了讓這些類中的方法都只讓ReentrantLock使用。


1.Sync
該類是AQS的子類,重寫了一些方法(AQS需要實現,公平鎖與非公平鎖通用),是NonfairSync與FairSync的父類。
接下如acquire(),tryAcquire(),release()等屬於AQS類的重要方法,在上一篇描述AQS的blog中已經詳細闡述,此處不再闡述。

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 6317671515068378041L;

        /*
         * 鎖狀態state是int型,讀寫分爲兩部分,各用一個無符號short來表示
         * 低位的表示寫鎖即獨享鎖,高位的表示讀鎖共享數
         */
        // 這個16是兩個字節,一個short的長度
        static final int SHARED_SHIFT   = 16;
        // 1左移16位,爲00000000 00000001 00000000 00000000
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        // 1左移16位,減1,爲65535,讀寫的獲取鎖的最大次數
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        // 右移16位,獲取c高位的16位,表示讀鎖的共享總數(高位2字節全0)
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        // 和兩個字節的全1字節與操作,高位2字節全0,獲取寫鎖的總數
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

        // 每個線程的計數器,保存讀鎖共享數
        static final class HoldCounter {
            int count = 0;
            final long tid = getThreadId(Thread.currentThread());
        }

        // ThreadLocal的子類
        static final class ThreadLocalHoldCounter
            extends ThreadLocal<HoldCounter> {
            // 初始化方法,返回HoldCounter
            public HoldCounter initialValue() {
                return new HoldCounter();
            }
        }

        // 讀線程的一個集合,但不包括最後一個讀線程和第一個讀線程
        private transient ThreadLocalHoldCounter readHolds;
        // 最後一個讀線程的計數
        private transient HoldCounter cachedHoldCounter;
        // 第一個讀線程
        private transient Thread firstReader = null;
        // 第一個讀線程的計數
        private transient int firstReaderHoldCount;

        Sync() {
            readHolds = new ThreadLocalHoldCounter();
            setState(getState()); // ensures visibility of readHolds
        }
        // 讀鎖的阻塞
        abstract boolean readerShouldBlock();

        // 寫鎖的阻塞
        abstract boolean writerShouldBlock();

        // 釋放寫鎖
        protected final boolean tryRelease(int releases) {
            if (!isHeldExclusively())
                // 當前線程不是owner線程,不能進行釋放
                throw new IllegalMonitorStateException();
            // 計算釋放後的狀態值    
            int nextc = getState() - releases;
            // 如果當前寫鎖釋放後,看是否還有寫鎖,沒有寫鎖返回true
            boolean free = exclusiveCount(nextc) == 0;
            if (free)
                // 沒有寫鎖了將鎖對象的當前owner置爲null
                setExclusiveOwnerThread(null);
            // 更新state的新值
            setState(nextc);
            return free;
        }

        // 嘗試獲取寫鎖
        protected final boolean tryAcquire(int acquires) {
            // 當前線程
            Thread current = Thread.currentThread();
            // 狀態c,包含讀鎖和寫鎖的總數
            int c = getState();
            // w表示寫鎖的總數
            int w = exclusiveCount(c);
            if (c != 0) {
                // 如果寫鎖爲0,說明當前有讀鎖(也可能是當前線程有讀鎖),不能獲取寫鎖
                // 如果寫鎖不爲0,但是當前線程不是owner線程不可重入,不能獲取寫鎖
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                // 寫鎖數量超過了65535報錯
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // 這裏已經說明寫鎖是當前線程可重入的了,直接設置state值,返回true
                setState(c + acquires);
                return true;
            }
            // c==0時,如果寫需要阻塞或者設置狀態失敗,返回false
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
            // 設置鎖的owner獨佔標識
            setExclusiveOwnerThread(current);
            return true;
        }

        // 嘗試釋放讀鎖
        protected final boolean tryReleaseShared(int unused) {
            // 當前線程current
            Thread current = Thread.currentThread();
            // 如果當前線程是第一個獲取讀鎖的
            if (firstReader == current) {
                // 當前線程讀鎖總數爲1,直接將firstReader置爲null
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                // 如果不爲1,那麼減掉1即可
                else
                    firstReaderHoldCount--;
            } else {
                // 最後一個獲取讀鎖的線程
                HoldCounter rh = cachedHoldCounter;
                // 如果當前線程也不是最後一個獲取讀鎖的線程,從ThreadLocal中取
                if (rh == null || rh.tid != getThreadId(current))
                    rh = readHolds.get();
                // 當前線程讀鎖的個數
                int count = rh.count;
                // 如果count==1,釋放了就爲0,直接在ThreadLocal中去掉當前線程
                if (count <= 1) {
                    readHolds.remove();
                    // count<=0,此時拋出不匹配釋放鎖的異常
                    if (count <= 0)
                        throw unmatchedUnlockException();
                }
                // 正常情況下,將當前線程的讀鎖count值減1即可。
                --rh.count;
            }
            for (;;) {
                int c = getState();
                // 高位減1,新的讀寫鎖值
                int nextc = c - SHARED_UNIT;
                // 嘗試設置state值,預測之前爲c,更新爲nextc
                if (compareAndSetState(c, nextc))
                    // 釋放讀鎖不會影響其他讀鎖,但是如果這時讀寫鎖都空閒,等待中的寫線程將開始執行
                    // 這裏只有讀寫鎖都釋放了,才返回true
                    return nextc == 0;
            }
        }

        // 釋放讀鎖的不匹配異常
        private IllegalMonitorStateException unmatchedUnlockException() {
            return new IllegalMonitorStateException(
                "attempt to unlock read lock, not locked by current thread");
        }

        // 嘗試獲取讀鎖
        protected final int tryAcquireShared(int unused) {
            // 當前線程
            Thread current = Thread.currentThread();
            // 鎖的state值
            int c = getState();
            // 如果有獨佔標識同時當前線程並不是獨佔線程時,直接返回-1
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            // 讀鎖的總數
            int r = sharedCount(c);
            // 如果讀不需要阻塞,同時讀鎖小於65535,並且能夠CAS設置c的值讀個數加1
            // 這裏的阻塞策略readerShouldBlock進行了判斷,有兩種情況:
            // 1.公平模式:如果AQS隊列前面有等待的結點,當前線程應該阻塞
            // 2.非公平模式:如果AQS前面有線程在等待寫鎖,當前線程應該阻塞(這樣做的原因是爲了防止寫飢餓)。
            // 出現這個阻塞情況,就不走下邊的if了,直接到最後走fullTryAcquireShared方法處理
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                // 讀鎖個數爲0,將當前線程作爲第一個讀線程單獨保存,不存在ThreadLocal中
                if (r == 0) {
                    firstReader = current;
                    // 當前線程即第一個讀線程的讀鎖總數置爲1
                    firstReaderHoldCount = 1;
                // 如果r!=0,說明有讀線程了,判斷當前線程是不是第一個讀線程
                } else if (firstReader == current) {
                    // 如果當前線程就是第一個讀線程,數量count加1即可
                    firstReaderHoldCount++;
                } else {
                    // 當前線程不是第一個讀線程,判斷是不是最後一個讀線程
                    HoldCounter rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current))
                        // 當前線程不是最後一個讀線程,從ThreadLocal中取線程
                        // 同時將最後一個讀線程更新爲當前線程
                        cachedHoldCounter = rh = readHolds.get();
                    // 這裏如果當前線程就是最後一個讀線程的話,如果count爲0
                    else if (rh.count == 0)
                        // 需要重新set當前線程(之前釋放時,readHolds.remove()進行過這個操作)
                        readHolds.set(rh);
                    // 將當前線程的count加1
                    rh.count++;
                }
                // 返回值1說明獲取讀鎖成功了
                return 1;
            }
            // 讀線程阻塞時,執行這個方法
            return fullTryAcquireShared(current);
        }

        // 該方法處理讀線程阻塞的情況
        final int fullTryAcquireShared(Thread current) {
            HoldCounter rh = null;
            for (;;) {
                int c = getState();
                // 獨佔標記存在且當前owner不是當前線程,不能重入
                if (exclusiveCount(c) != 0) {
                    if (getExclusiveOwnerThread() != current)
                        return -1;
                // 沒有寫鎖存在時,如果讀阻塞
                // 這裏的阻塞策略,如果:1.公平模式:如果當前AQS隊列前面有等待的結點,返回false;2.非公平模式:如果
// AQS前面有線程在等待寫鎖,返回false(這樣做的原因是爲了防止寫飢餓)。
                } else if (readerShouldBlock()) {
                    // 如果當前線程是第一個讀線程
                    if (firstReader == current) {

                    } else {
                        if (rh == null) {
                            // 優先賦值成上一次獲取讀鎖成功的cache,即最後一個讀鎖
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != getThreadId(current)) {
                                // 如果和當前線程不匹配,從ThreadLocal中取
                                rh = readHolds.get();
                                if (rh.count == 0)
                                    readHolds.remove();
                            }
                        }
                        // 不是讀鎖重入的情況,返回-1
                        if (rh.count == 0)
                            return -1;
                    }
                }
                // 如果讀鎖總數爲65535,報錯
                if (sharedCount(c) == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // 如果CAS將c的讀鎖總數增加1成功
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    // 如果讀鎖數量爲0,當前線程作爲第一個線程存起來
                    if (sharedCount(c) == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    // 當前線程爲第一個獲取讀鎖的線程,數量加1
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    // 其他情況,和之前的方法同樣原理
                    } else {
                        if (rh == null)
                            rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current))
                            rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                        cachedHoldCounter = rh; // cache for release
                    }
                    return 1;
                }
            }
        }

        // 和tryAcquire基本一致,去掉了考慮阻塞部分,相當於非公平模式的獲取寫鎖
        final boolean tryWriteLock() {
            Thread current = Thread.currentThread();
            int c = getState();
            if (c != 0) {
                int w = exclusiveCount(c);
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                if (w == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
            }
            if (!compareAndSetState(c, c + 1))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        }

        // 和tryAcquireShared函數基本一致,去掉了考慮阻塞部分,相當於非公平模式的獲取讀鎖
        final boolean tryReadLock() {
            Thread current = Thread.currentThread();
            for (;;) {
                int c = getState();
                if (exclusiveCount(c) != 0 &&
                    getExclusiveOwnerThread() != current)
                    return false;
                int r = sharedCount(c);
                if (r == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    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 true;
                }
            }
        }

        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        final Thread getOwner() {
            return ((exclusiveCount(getState()) == 0) ?
                    null :
                    getExclusiveOwnerThread());
        }

        final int getReadLockCount() {
            return sharedCount(getState());
        }

        final boolean isWriteLocked() {
            return exclusiveCount(getState()) != 0;
        }

        final int getWriteHoldCount() {
            return isHeldExclusively() ? exclusiveCount(getState()) : 0;
        }

        final int getReadHoldCount() {
            if (getReadLockCount() == 0)
                return 0;

            Thread current = Thread.currentThread();
            if (firstReader == current)
                return firstReaderHoldCount;

            HoldCounter rh = cachedHoldCounter;
            if (rh != null && rh.tid == getThreadId(current))
                return rh.count;

            int count = readHolds.get().count;
            if (count == 0) readHolds.remove();
            return count;
        }

        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            readHolds = new ThreadLocalHoldCounter();
            setState(0); // reset to unlocked state
        }

        final int getCount() { return getState(); }
    }

此靜態內部類是ReentrantReadWriteLock的關鍵所在,過程已經在註釋中詳細描述,在此說明設計核心思想:

如何表示多個讀鎖與單個寫鎖 :由於state字段是32位的int,在次將state一分爲2,用高16位記錄讀鎖(共享鎖)的狀態,低16位保存寫鎖(獨佔鎖)的狀態,因此鎖的數量上限都是65535
如何表示每個讀鎖、寫鎖的重入次數:可以把線程重入讀鎖的次數作爲值存在 ThreadLocal 中

2.NonfairSync與FairSync

    static final class NonfairSync extends Sync {
        final boolean writerShouldBlock() {
            return false; // writers can always barge
        }
        final boolean readerShouldBlock() {
            return apparentlyFirstQueuedIsExclusive();
        }
    }
    static final class FairSync extends Sync {
        final boolean writerShouldBlock() {
            return hasQueuedPredecessors();
        }
        final boolean readerShouldBlock() {
            return hasQueuedPredecessors();
        }
    }

此處將公平鎖與非公平鎖放在一處,因爲大多數邏輯已經在它們的父類Sync中實現,此處各只有兩個方法:

  1. writerShouldBlock :寫鎖是阻塞進入等待隊列(true)還是直接獲取鎖(false)。在非公平鎖中,直接返回false;公平鎖中,若無等待線程則返回false,有等待線程返回true
  2. readerShouldBlock:讀鎖是阻塞進入等待隊列(true)還是直接獲取鎖(false)。在非公平鎖中,如果隊列的head.next正在等待獨佔鎖(寫鎖),則返回true,否則返回false;公平鎖中,若無等待線程則返回false,有等待線程返回true

3.ReadLock

public static class ReadLock implements Lock, java.io.Serializable {
        private final Sync sync;

        protected ReadLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        public void lock() {
            sync.acquireShared(1);
        }

        public void lockInterruptibly() throws InterruptedException {
            sync.acquireSharedInterruptibly(1);
        }

        public boolean tryLock() {
            return sync.tryReadLock();
        }

        public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
        }

        public void unlock() {
            sync.releaseShared(1);
        }

        public Condition newCondition() {
            throw new UnsupportedOperationException();
        }

    }

內部有一屬性爲sync,是從外部類繼承過來,使用同一syn。使用共享鎖,至於方法與ReentrantLock類似,同名方法作用一樣,實現都是調用AQS以及Syn及子類方法,再次不贅述。
唯一需要注意的是,condition隊列只支持獨佔鎖,故此處不支持condition相關操作,直接拋出異常。
4.WriteLock

public static class WriteLock implements Lock, java.io.Serializable {
        private final Sync sync;
        protected WriteLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }
        //獲取鎖。若未獲取則將線程阻塞等待
        public void lock() {
            sync.acquire(1);
        }
        //獲取鎖。若未獲取則將線程阻塞等待,直到獲取鎖。如果有中斷請求就會產生中斷異常
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireInterruptibly(1);
        }
        //嘗試立刻獲取鎖
        public boolean tryLock( ) {
            return sync.tryWriteLock();
        }
        //嘗試立刻在指定時間內獲取鎖
        public boolean tryLock(long timeout, TimeUnit unit)
                throws InterruptedException {
            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
        }
        //釋放鎖
        public void unlock() {
            sync.release(1);
        }
        //獲取等待隊列
        public Condition newCondition() {
            return sync.newCondition();
        }
        //獲取寫鎖的個數
        public int getHoldCount() {
            return sync.getWriteHoldCount();
        }
    }

內部有一屬性爲sync,是從外部類繼承過來,使用同一syn。使用獨佔鎖,至於方法與ReentrantLock類似,同名方法作用一樣,實現都是調用AQS以及Syn及子類方法,再次不贅述。

三、構造器
ReentrantReadWriteLock對外提供兩個構造器:

public ReentrantReadWriteLock() {
    this(false);
}
public ReentrantReadWriteLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
    readerLock = new ReadLock(this);
    writerLock = new WriteLock(this);
}

protected ReadLock(ReentrantReadWriteLock lock) {
    sync = lock.sync;
}
protected WriteLock(ReentrantReadWriteLock lock) {
    sync = lock.sync;
}

public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }
  1. ReentrantReadWriteLock(),默認構造器,默認使用非公平鎖,故上文中描述該類默認使用非公平鎖
  2. ReentrantReadWriteLock(boolean fair),帶參構造器,傳入true則是公平鎖,false是非公平鎖

四、對外提供方法
ReentrantReadWriteLock提供了一系列方法,都是基於AQS以及上述Sync系列靜態內部類實現,實現原理較簡單,作用見註釋,不一一詳述。

// 返回當前擁有寫入鎖的線程,如果沒有這樣的線程,則返回 null。
protected Thread getOwner()
// 返回一個 collection,它包含可能正在等待獲取讀取鎖的線程。
protected Collection<Thread> getQueuedReaderThreads()
// 返回一個 collection,它包含可能正在等待獲取讀取或寫入鎖的線程。
protected Collection<Thread> getQueuedThreads()
// 返回一個 collection,它包含可能正在等待獲取寫入鎖的線程。
protected Collection<Thread> getQueuedWriterThreads()
// 返回等待獲取讀取或寫入鎖的線程估計數目。
int getQueueLength()
// 查詢當前線程在此鎖上保持的重入讀取鎖數量。
int getReadHoldCount()
// 查詢爲此鎖保持的讀取鎖數量。
int getReadLockCount()
// 返回一個 collection,它包含可能正在等待與寫入鎖相關的給定條件的那些線程。
protected Collection<Thread> getWaitingThreads(Condition condition)
// 返回正等待與寫入鎖相關的給定條件的線程估計數目。
int getWaitQueueLength(Condition condition)
// 查詢當前線程在此鎖上保持的重入寫入鎖數量。
int getWriteHoldCount()
// 查詢是否給定線程正在等待獲取讀取或寫入鎖。
boolean hasQueuedThread(Thread thread)
// 查詢是否所有的線程正在等待獲取讀取或寫入鎖。
boolean hasQueuedThreads()
// 查詢是否有些線程正在等待與寫入鎖有關的給定條件。
boolean hasWaiters(Condition condition)
// 如果此鎖將公平性設置爲 ture,則返回 trueboolean isFair()
// 查詢是否某個線程保持了寫入鎖。
boolean isWriteLocked()
// 查詢當前線程是否保持了寫入鎖。
boolean isWriteLockedByCurrentThread()
// 返回用於讀取操作的鎖。
ReentrantReadWriteLock.ReadLock readLock()
// 返回用於寫入操作的鎖。
ReentrantReadWriteLock.WriteLock writeLock()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章