成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

圖解AQS原理之ReentrantLock詳解-公平鎖

Taonce / 2466人閱讀

摘要:概述前面已經(jīng)講解了關(guān)于的非公平鎖模式,關(guān)于非公平鎖,內(nèi)部其實(shí)告訴我們誰(shuí)先爭(zhēng)搶到鎖誰(shuí)就先獲得資源,下面就來(lái)分析一下公平鎖內(nèi)部是如何實(shí)現(xiàn)公平的如果沒(méi)有看過(guò)非公平鎖的先去了解下非公平鎖,因?yàn)檫@篇文章前面不會(huì)講太多內(nèi)部結(jié)構(gòu),直接會(huì)對(duì)源碼進(jìn)行分析前文

概述

前面已經(jīng)講解了關(guān)于AQS的非公平鎖模式,關(guān)于NonfairSync非公平鎖,內(nèi)部其實(shí)告訴我們誰(shuí)先爭(zhēng)搶到鎖誰(shuí)就先獲得資源,下面就來(lái)分析一下公平鎖FairSync內(nèi)部是如何實(shí)現(xiàn)公平的?如果沒(méi)有看過(guò)非公平鎖的先去了解下非公平鎖,因?yàn)檫@篇文章前面不會(huì)講太多內(nèi)部結(jié)構(gòu),直接會(huì)對(duì)源碼進(jìn)行分析

前文連接地址:圖解AQS原理之ReentrantLock詳解-非公平鎖

本文分析的JDK版本是1.8

溫馨提示:讀本文內(nèi)容建議結(jié)合之前寫的非公平,前篇設(shè)計(jì)了很多基礎(chǔ)性內(nèi)容

源碼分析

在源碼分析之前,我們先來(lái)看一下ReentrantLock如何切換獲取鎖的模式呢?其實(shí)是在構(gòu)造器中傳遞指定的類型變量來(lái)控制使用鎖的方式,如下所示:

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

當(dāng)fair參數(shù)指定為true時(shí),代表的是公平鎖,如果指定為false則使用的非公平,無(wú)參的構(gòu)造函數(shù)默認(rèn)使用的是非公平模式,如下所示:

public ReentrantLock() {
    sync = new NonfairSync();
}

接下來(lái)我們以一個(gè)例子來(lái)進(jìn)行后面的說(shuō)明:

public class ReentrantLockDemo {

    public static void main(String[] args) throws Exception {
        AddDemo runnalbeDemo = new AddDemo();
        Thread thread = new Thread(runnalbeDemo::add);
        thread.start();
        Thread.sleep(500);
        Thread thread1 = new Thread(runnalbeDemo::add);
        thread1.start();
        System.out.println(runnalbeDemo.getCount());
    }

    private static class AddDemo {
        private final AtomicInteger count = new AtomicInteger();
        private final ReentrantLock reentrantLock = new ReentrantLock(true);
        private final Condition condition = reentrantLock.newCondition();

        private void add() {
            try {
                reentrantLock.lockInterruptibly();
                count.getAndIncrement();
            } catch (Exception ex) {
                System.out.println("線程被中斷了");
            } finally {
//                reentrantLock.unlock();
            }
        }

        int getCount() {
            return count.get();
        }
    }
}

我們通過(guò)源碼可以看到這里我們啟動(dòng)了兩個(gè)線程,兩個(gè)線程分別進(jìn)行同步鎖操作,這里我并沒(méi)有釋放掉鎖,因?yàn)榉奖惴治鲫?duì)列的情況,當(dāng)然你也可以在內(nèi)部寫一個(gè)死循環(huán),不釋放鎖就可以了,我這里簡(jiǎn)單的不釋放鎖,使用的是可中斷的獲取鎖操作方法lockInterruptibly,這里內(nèi)部的原理我們上一篇文章中已經(jīng)講解過(guò)了,這里并不過(guò)多的去分析內(nèi)部原理,這個(gè)ReentrantLocklockInterruptibly調(diào)用內(nèi)部類AQSacquireInterruptibly,但是其實(shí)是FairSync內(nèi)部類繼承了內(nèi)部類Sync,而內(nèi)部類Sync有繼承了AbstractQueuedSynchronizer簡(jiǎn)稱AQS,acquireInterruptibly源碼信息如下所示:

public final void acquireInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}

這里我們通過(guò)上一篇文章得知tryAcquire是需要子類去實(shí)現(xiàn)的方法,我們?cè)诶又兄付耸褂玫氖枪芥i,所以tryAcquire方法的實(shí)現(xiàn)是在ReentrentLockFairSync類中,我們來(lái)具體看一下這個(gè)方法,重點(diǎn)也在這個(gè)方法中其他的其實(shí)都是一樣的,因?yàn)橛玫姆椒ǘ紩?huì)一樣的非公平和公平鎖的調(diào)用,唯獨(dú)不一樣的就是子類實(shí)現(xiàn)的方法是不相同的,接下來(lái)我們就來(lái)看一下公平鎖的tryAcquire是如何實(shí)現(xiàn)的?

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (!hasQueuedPredecessors() &&                                //判斷是否有等待的線程在隊(duì)列中
            compareAndSetState(0, acquires)) {                //嘗試爭(zhēng)搶鎖操作
            setExclusiveOwnerThread(current);                    //設(shè)置當(dāng)前線程獨(dú)占鎖資源
            return true;                                                            //獲得鎖成功
        }
    }
    else if (current == getExclusiveOwnerThread()) {    //當(dāng)前線程和獨(dú)占鎖資源的線程一致,則可以重入
        int nextc = c + acquires;                                            //state遞增
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);                                                            //設(shè)置state狀態(tài)
        return true;                                                                    //獲得鎖成功
    }
    return false;                                                                            //獲得鎖失敗
}

對(duì)比非公平鎖的NonfairSync類的tryAcquire方法,其實(shí)就是在鎖可用的情況下增加了一個(gè)判斷條件,這個(gè)判斷方法就是hasQueuedPredecessors,從方法的名稱來(lái)看說(shuō)的是有等待的線程隊(duì)列,換句話說(shuō)已經(jīng)有人在排隊(duì)了,新來(lái)的線程你就不能加塞,而非公平模式的誰(shuí)先爭(zhēng)搶到鎖就是誰(shuí)的,管你先來(lái)不先來(lái),接下來(lái)我們具體看一下這個(gè)

hasQueuedPredecessors方法源碼:

public final boolean hasQueuedPredecessors() {
    // The correctness of this depends on head being initialized
    // before tail and on head.next being accurate if the current
    // thread is first in queue.
    Node t = tail; // 獲得尾節(jié)點(diǎn)
    Node h = head; // 獲得頭節(jié)點(diǎn)
    Node s;
    return h != t &&    //頭節(jié)點(diǎn)和尾節(jié)點(diǎn)相同代表隊(duì)列為空        
        ((s = h.next) == null || s.thread != Thread.currentThread());    //頭節(jié)點(diǎn)的next節(jié)點(diǎn)為空代表頭節(jié)點(diǎn),以及s.thread不是當(dāng)前線程不是自己的話代表隊(duì)列中存在元素
}

通過(guò)上面的源碼信息,可以得出其實(shí)內(nèi)部主要就是判斷有沒(méi)有排隊(duì)等待的節(jié)點(diǎn),隊(duì)列是否為空,如果為空的話則可以爭(zhēng)搶鎖,如果隊(duì)列不為空,伙計(jì)你必須老老實(shí)實(shí)給我排隊(duì)去,除非占有鎖的線程和請(qǐng)求鎖的線程是一樣的,否則還是老老實(shí)實(shí)排隊(duì)去,這就是公平模式的鎖操作,還有一個(gè)lock方法,公平模式的lock方法,沒(méi)有直接上來(lái)先獲取鎖,而是先嘗試獲得鎖直接調(diào)用AQSaquire方法進(jìn)行嘗試獲取鎖,下面是FairSync源碼:

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1);                                    //這里直接調(diào)用了aquire并沒(méi)有嘗試修改state狀態(tài)
    }

    /**
     * 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;
    }
}
結(jié)束語(yǔ)

本內(nèi)容主要是結(jié)合上篇內(nèi)容的一個(gè)續(xù)篇,可以結(jié)合上篇然后再看下篇會(huì)比較清晰些。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74749.html

相關(guān)文章

  • 圖解AQS原理ReentrantLock詳解-非公平

    摘要:內(nèi)部提供了兩種的實(shí)現(xiàn),一種公平模式,一種是非公平模式,如果沒(méi)有特別指定在構(gòu)造器中,默認(rèn)是非公平的模式,我們可以看一下無(wú)參的構(gòu)造函數(shù)。 概述 并發(fā)編程中,ReentrantLock的使用是比較多的,包括之前講的LinkedBlockingQueue和ArrayBlockQueue的內(nèi)部都是使用的ReentrantLock,談到它又不能的不說(shuō)AQS,AQS的全稱是AbstractQueue...

    Clect 評(píng)論0 收藏0
  • ReentrantLockAQS原理與源碼詳解

    摘要:所以大家看下面的圖,就是線程跑過(guò)來(lái)加鎖的一個(gè)過(guò)程。好線程現(xiàn)在就重新嘗試加鎖,這時(shí)還是用操作將從變?yōu)?,此時(shí)就會(huì)成功,成功之后代表加鎖成功,就會(huì)將設(shè)置為。此外,還要把加鎖線程設(shè)置為線程自己,同時(shí)線程自己就從等待隊(duì)列中出隊(duì)了。 ReentrantLock和AQS的關(guān)系 ReentrantLock使用 showImg(https://segmentfault.com/img/bVbkZr4?...

    elisa.yang 評(píng)論0 收藏0
  • Java 重入 ReentrantLock 原理分析

    摘要:的主要功能和關(guān)鍵字一致,均是用于多線程的同步。而僅支持通過(guò)查詢當(dāng)前線程是否持有鎖。由于和使用的是同一把可重入鎖,所以線程可以進(jìn)入方法,并再次獲得鎖,而不會(huì)被阻塞住。公平與非公平公平與非公平指的是線程獲取鎖的方式。 1.簡(jiǎn)介 可重入鎖ReentrantLock自 JDK 1.5 被引入,功能上與synchronized關(guān)鍵字類似。所謂的可重入是指,線程可對(duì)同一把鎖進(jìn)行重復(fù)加鎖,而不會(huì)被阻...

    lx1036 評(píng)論0 收藏0
  • Java多線程進(jìn)階(七)—— J.U.Clocks框架:AQS獨(dú)占功能剖析(2)

    摘要:開(kāi)始獲取鎖終于輪到出場(chǎng)了,的調(diào)用過(guò)程和完全一樣,同樣拿不到鎖,然后加入到等待隊(duì)列隊(duì)尾然后,在阻塞前需要把前驅(qū)結(jié)點(diǎn)的狀態(tài)置為,以確保將來(lái)可以被喚醒至此,的執(zhí)行也暫告一段落了安心得在等待隊(duì)列中睡覺(jué)。 showImg(https://segmentfault.com/img/remote/1460000016012467); 本文首發(fā)于一世流云的專欄:https://segmentfault...

    JayChen 評(píng)論0 收藏0
  • Java多線程進(jìn)階(三)—— J.U.Clocks框架:ReentrantLock

    摘要:公平策略在多個(gè)線程爭(zhēng)用鎖的情況下,公平策略傾向于將訪問(wèn)權(quán)授予等待時(shí)間最長(zhǎng)的線程。使用方式的典型調(diào)用方式如下二類原理的源碼非常簡(jiǎn)單,它通過(guò)內(nèi)部類實(shí)現(xiàn)了框架,接口的實(shí)現(xiàn)僅僅是對(duì)的的簡(jiǎn)單封裝,參見(jiàn)原理多線程進(jìn)階七鎖框架獨(dú)占功能剖析 showImg(https://segmentfault.com/img/remote/1460000016012582); 本文首發(fā)于一世流云的專欄:https...

    jasperyang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Taonce

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<