源碼分析之ReentrantLock

ReentrantLock類是屬于java.util.concurrent的。實現(xiàn)了Lock, java.io.Serializable兩個接口,是一個可重入的互斥鎖,所謂可重入是線程可以重復(fù)獲取已經(jīng)持有的鎖。

 /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
abstract static class Sync extends AbstractQueuedSynchronizer

ReentrantLock實現(xiàn)鎖的機(jī)制是通過Sync進(jìn)行操作的。Sync類是繼承AbstractQueuedSynchronizer類的。這也就表明ReentrantLock是基于AQS的實現(xiàn)的?!?/p>

Sync,FairSyncNonFairSync都是ReentrantLock的靜態(tài)內(nèi)部類。FairSyncNonFairSync又是Sync具體實現(xiàn)類,分別對應(yīng)的是公平鎖和非公平鎖,公平主要是指按照FIFO原則順序獲取鎖,非公平可以根據(jù)定義的規(guī)則來選擇獲得鎖。

NonFairSync 源碼分析

非公平鎖NonFairSyncReentrantLock默認(rèn)的實現(xiàn)方式。這里可以看一下它的lock實現(xiàn)過程:

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

  • 首先通過CAS更新state狀態(tài),如果更新成功,則獲取鎖,設(shè)定當(dāng)前線程為鎖的擁有者。
    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
  • 如果更新失敗,表明當(dāng)前鎖被其他線程占有。則會調(diào)用acquire(1)方法。acquire具體實現(xiàn)如下:
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
        

tryAcquire過程,將再次嘗試獲取鎖,其中tryAcquire在靜態(tài)內(nèi)部類NonfairSync類中被重寫,具體的實現(xiàn)是SyncnonfairTryAcquire方法:

        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;
        }

其主要過程是先獲取state的值,如果等于0,則通過CAS更新state的值。如果state不為0,則判斷當(dāng)前線程是否是鎖的持有者,如果是,則將state加1,返回true。

如果tryAcquire仍然失敗的話,首先會調(diào)用addWaiter(Node.EXCLUSIVE),將當(dāng)前線程加入到等待隊列的尾部。然后會調(diào)用acquireQueued方法,acquireQueued的作用主要是用來阻塞線程的:

    /**
     * Acquires in exclusive uninterruptible mode for thread already in
     * queue. Used by condition wait methods as well as acquire.
     *
     * @param node the node
     * @param arg the acquire argument
     * @return {@code true} if interrupted while waiting
     */
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

這里是一個循環(huán)自旋操作,在阻塞線程之前,首先判斷線程自身前面的節(jié)點是否是head節(jié)點,如果是,則重新去獲取鎖,獲取成功后,返回,并取消不斷獲取的過程。如果不是,調(diào)用shouldParkAfterFailedAcquire方法去判斷是否應(yīng)該阻塞當(dāng)前線程,主要是通過節(jié)點的waitStatus來進(jìn)行判斷。

FairSync 源碼分析

公平鎖FairSync和非公平鎖NonFairSync的實現(xiàn)很相似,這里比較一下兩者的差別。

  • FairSynclock方法中沒有像NonFairSync中先去通過CAS操作state去獲取鎖,而是直接通過tryAcquire去獲取鎖。
        final void lock() {
            acquire(1);
        }
  • FairSync版本tryAcquire在獲取鎖的過程中,需要先判斷隊列中是否有其他等待的線程,如果沒有,才回去嘗試獲取鎖。
        /**
         * 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;
        }

unlock() 釋放鎖

釋放鎖沒有區(qū)分公平和非公平的。主要的工作就是減小state的值。當(dāng)state等0的時候,釋放鎖并喚醒隊里中其他線程來獲取鎖。

        public void unlock() {
            sync.release(1);
        }
        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) {
            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;
        }

總結(jié)

  • ReentrantLock是通過AQSstate字段來判斷所是否被占用。
  • 公平非公平的差別是在于獲取鎖的方式是否是按照順序的。
  • state操作是通過CAS實現(xiàn)的。通過隊列來實現(xiàn)因搶占鎖被阻塞的隊列。
  • 在阻塞線程的過程中,AQS有自旋的過程,并非是獲取不到鎖就直接阻塞。

如有紕漏,還望指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 上一篇文章《基于CAS操作的Java非阻塞同步機(jī)制》 分析了非同步阻塞機(jī)制的實現(xiàn)原理,本篇將分析一種以非同步...
    Mars_M閱讀 4,908評論 5 9
  • 1. ReentrantLock 定義 ReentrantLock 是 JUC 中提供的可中斷, 可重入獲取, 支...
    愛吃魚的KK閱讀 4,244評論 0 7
  • 一個簡單的單例示例 單例模式可能是大家經(jīng)常接觸和使用的一個設(shè)計模式,你可能會這么寫 publicclassUnsa...
    Martin說閱讀 2,393評論 0 6
  • 一、前言 借用Java并發(fā)編程實踐中的話"編寫正確的程序并不容易,而編寫正常的并發(fā)程序就更難了",相比于順序執(zhí)行的...
    運維開發(fā)筆記閱讀 419評論 0 2
  • 感賞今天自己能及時認(rèn)識到自己的沖動,寫了舒緩日志 感賞兒子在發(fā)脾氣后能及時認(rèn)識到自己的錯誤,并且非常懂事的去做自己...
    清荷之露閱讀 176評論 0 0

友情鏈接更多精彩內(nèi)容