JUC下的鎖-ReentrantLock

ReentrantLock意思為可重入鎖,指的是一個(gè)線程能夠?qū)σ粋€(gè)臨界資源重復(fù)加鎖。
借用美團(tuán)技術(shù)博客的一張圖說(shuō)明它和Synchronized的區(qū)別


區(qū)別

ReentrantLock的主要結(jié)構(gòu)

????ReentrantLock沒(méi)有直接繼承AbstractQueuedSynchronizer,而是Sync繼承的。Sync又是個(gè)抽象類,有NonfairSync和FairSync兩個(gè)子類??梢钥吹侥J(rèn)的構(gòu)造函數(shù)是非公平鎖,另一個(gè)構(gòu)造函數(shù)則指定公平/非公平。
????全局變量sync在構(gòu)造函數(shù)里被賦值,在加鎖、解鎖等操作的時(shí)候使用sync里面的API

在開(kāi)始之前要知道公平鎖和非公平鎖的區(qū)別

????公平鎖:多個(gè)線程按照申請(qǐng)鎖的順序去獲得鎖,線程會(huì)直接進(jìn)入隊(duì)列去排隊(duì),永遠(yuǎn)都是隊(duì)列的第一位才能得到鎖。
????優(yōu)點(diǎn):所有的線程都能得到資源,不會(huì)餓死在隊(duì)列中。
????缺點(diǎn):吞吐量會(huì)下降很多,隊(duì)列里面除了第一個(gè)線程,其他的線程都會(huì)阻塞,cpu喚醒阻塞線程的開(kāi)銷會(huì)很大
????非公平:多個(gè)線程去獲取鎖的時(shí)候,會(huì)直接去嘗試獲取,獲取不到,再去進(jìn)入等待隊(duì)列,如果能獲取到,就直接獲取到鎖。
????優(yōu)點(diǎn):可以減少CPU喚醒線程的開(kāi)銷,整體的吞吐效率會(huì)高點(diǎn),CPU也不必取喚醒所有線程,會(huì)減少喚起線程的數(shù)量。
????缺點(diǎn):可能會(huì)導(dǎo)致隊(duì)列中間的線程一直獲取不到鎖或者長(zhǎng)時(shí)間獲取不到鎖,導(dǎo)致餓死。

加鎖API
  public void lock() {
        sync.lock();
    }
FairSync實(shí)現(xiàn)
 static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
          // 調(diào)用AQS的acquire,AQS的acquire又會(huì)調(diào)用子類的tryAcquire
            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();
            // 獲取AQS的同步狀態(tài),如果鎖沒(méi)有被占用(0沒(méi)占用,1占用),那么獲取鎖
            if (c == 0) {
                // 如果沒(méi)有其他線程比當(dāng)前線程等待的時(shí)間更長(zhǎng),那么就把AQS的同步狀態(tài)置為1
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                     // 設(shè)置同步狀態(tài)成功后,把當(dāng)前線程設(shè)置為獨(dú)占線程,獲取鎖成功
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 鎖被占用,并且是自己占用的話,就加重入次數(shù),否則,獲取鎖失敗返回false
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }
NonfairSync實(shí)現(xiàn)
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))
                setExclusiveOwnerThread(Thread.currentThread());
            else // 如果CAS更新同步狀態(tài)失敗再去acquire,acquire又會(huì)調(diào)用tryAcquire
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            // 鎖沒(méi)沒(méi)有被占用則獲取鎖
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 獲取鎖的是自己則累加重入次數(shù)
            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;
        }
響應(yīng)中斷獲取鎖
public void lockInterruptibly() throws InterruptedException {
        // 調(diào)用AQS的acquireInterruptibly,如果當(dāng)前線程沒(méi)有被中斷則獲取鎖
        sync.acquireInterruptibly(1);
    }
有返回值的獲取鎖
  public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
  }

 final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            // 沒(méi)有其他線程獲取鎖,則將當(dāng)前線程設(shè)置為獨(dú)享線程,返回true
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 當(dāng)前線程已經(jīng)擁有鎖了,重入
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                // state設(shè)置為重入的層數(shù)
                setState(nextc);
                return true;
            }

          // 沒(méi)拿到鎖返回false
            return false;
        }
    }

釋放鎖API

釋放鎖是不分公平和非公平的,release是AQS的方法,不允許子類重寫。但是其中的tryRelease強(qiáng)制子類重寫

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

public final boolean release(int arg) {
        // 釋放鎖
        if (tryRelease(arg)) { 
            // 如果還有頭節(jié)點(diǎn),并且頭節(jié)點(diǎn)的waitStatus不是初始值,則喚醒后繼節(jié)點(diǎn)的線程
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

 protected final boolean tryRelease(int releases) {
            // 當(dāng)前state-releases=還剩下的重入層數(shù)
            int c = getState() - releases;
            // 如果不是當(dāng)前線程獨(dú)占,那么不允許當(dāng)前線程釋放鎖
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
         
            boolean free = false;
            // 如果重入層數(shù)是0了,那么就代表當(dāng)前線程沒(méi)鎖了,free=true
            if (c == 0) {
                free = true;
                // 清空獨(dú)占線程
                setExclusiveOwnerThread(null);
            }
            // 設(shè)置state,不管state是0還是非0
            setState(c);
            // 返回free
            return free;
        }

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

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

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