ReentrantLock源碼學習

上文學習了JUC的AQS工具,下面看下可重入顯示鎖的實現(如何基於AQS),要看ReentrantLock,還是先看下顯示鎖內部對AQS的幾種子類實現。

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

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();//lock留給子類實現

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
        
        final boolean nonfairTryAcquire(int acquires) {//實現非公平獲取
            final Thread current = Thread.currentThread();
            int c = getState();//AQS的state屬性,這裏被用來當作鎖資源
            if (c == 0) {//state在AQS中默認爲0,說明此時到達的是第一個線程,尚未有線程修改過state,acquires是要獲取的資源數,在互斥鎖下爲1
                if (compareAndSetState(0, acquires)) {//CAS修改state爲acquires
                    setExclusiveOwnerThread(current);//將當前線程賦值給AQS的exclusiveOwnerThread屬性
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {//state!=0說明已有線程獲取了資源,檢查AQS的互斥線程是否是線程自身
                int nextc = c + acquires;//將請求資源數增加
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);//更改state(未使用cas,因爲只有exclusiveOwnerThread可以修改此值)
                return true;
            }
            return false;
        }

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())//只有exclusiveOwnerThread當前擁有着纔可以release釋放
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {//state==0,則當前exclusiveOwnerThread線程已釋放所有資源
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {//條件對象,擁有await和signal等方法,用於條件上的線程阻塞和喚醒
            return new ConditionObject();
        }

        // Methods relayed from outer class

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

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

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

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }
非公平Sync和公平Sync實現:
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))//cas(0,1)返回true則獲取成功將此線程設置爲exclusiveOwnerThread線程
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);//調用AQS的acquires方法
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);//調用Sync的方法
        }
    }
static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {//公平獲取方法,對比非公平的lock
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        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;
        }
    }

對於AQS的使用,我們直接從ReentrantLock的lock和unlock方法看起就好
public void lock() {
        sync.lock();
    }
 public void unlock() {
        sync.release(1);
    }


其實內部的源碼,還是我們前面看到的,AQS的內容以及公平和非公平兩種子類的實現,ReentrantLock的實現就是調用這些方法。下面上一張我畫的圖。

線程ABC獲取lock,隊列的變過程等,以及釋放鎖的過程。

其中BC都調用了park阻塞自身,然後添加到隊尾,當前線程釋放鎖時,清空exclusiveOwnerThread,並喚醒head的後繼,調用unpark。

另外,當A線程運行結束,釋放鎖之後,喚醒了B節點,這裏只是進行了喚醒,卻沒有任何將head出隊的操作,這讓我很疑惑,當B線程被喚醒後,去競爭鎖失敗,豈不是又會將一個包含了B線程的新節點添加到隊尾?並且head節點的後繼仍然是剛纔的B節點?

當B節點線程B被喚醒後,仍然還在循環內,此時直接在acquireQueued內的循環內執行,並不會新增加節點,而當此線程獲取成功時,會將head出隊,B作爲頭節點。

這裏要感謝高級交流羣的廣州-浪子,幫我解答了我的問題:




獨佔模式下,假設現在有 A B C三個線程。 

A線程先進來,成功獲取鎖, tryAcuire  = true = !true = false. 此時A線程不需要進入等待隊列

B線程進來,tryAcquire= false= !false= true.進入acquireQueued(addWaiter(Node.EXCLUSIVE), arg)

跳過入隊


如果B線程被喚醒後,且能成功tryAcuire的話,那麼就成功出隊。tryAcuire失敗的話再次阻塞(爲什麼會失敗?可能他這次被喚醒的資源給別的線程搶去了)




發佈了44 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章