ReetrantLock

總結(jié)一下ReetrantLock

ReetrantLock分為公平鎖兴猩,以及非公平鎖介陶,默認(rèn)情況下是非公平鎖嵌言,分別總結(jié)一下這兩種使用的異同點(diǎn)。

ReentrantLock 的成員變量有

private final Sync sync;
//這個(gè)就是AQS
abstract static class Sync extends AbstractQueuedSynchronizer 

首先使用ReetrantLock的時(shí)候,會(huì)先new一個(gè)出來(lái)這時(shí)候,默認(rèn)的構(gòu)造函數(shù)是構(gòu)造一個(gè)非公平鎖

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

然后嘗試調(diào)用加鎖的時(shí)候箭跳,其實(shí)調(diào)用的是sync的lock方法

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

然后就會(huì)調(diào)用非公平鎖的lock方法

final void lock() {
            //首先進(jìn)行cas操作箕戳,把state的狀態(tài)從0變成1舀射,非公平鎖和公平鎖的區(qū)別就是,首先會(huì)進(jìn)行一次CAS操作,如果線程拿到了鎖氧猬,那就搶占了資源,這樣的話坏瘩,可能新的線程會(huì)優(yōu)先于已經(jīng)在隊(duì)列里的那些線程拿到鎖盅抚,這樣不是按順序的,就是非公平的了
            if (compareAndSetState(0, 1))
                //如果cas成功了倔矾,aqs的持有線程就是當(dāng)前的線程
                setExclusiveOwnerThread(Thread.currentThread());
            else
                //沒(méi)有拿到鎖泉哈,那就調(diào)用的AQS中的acquire
                acquire(1);
        }

如果當(dāng)前線程沒(méi)有拿到鎖,那么就去執(zhí)行acquire(1)方法

/**
     * 這里有幾個(gè)步驟
     * 1.先嘗試獲取一下tryAcquire破讨,
     * 2.如果獲取不到鎖丛晦,那就將當(dāng)前線程添加到節(jié)點(diǎn)中addWaiter(Node.EXCLUSIVE) 添加到了CLH中
     * 3.acquireQueued通過(guò)自旋的方式不斷的獲取鎖
     * 4.最終拿到了之后會(huì)中斷自己
     * @param arg
     */
    public final void acquire(int arg) {
        //如果沒(méi)有獲取成功,那么就要添加到隊(duì)列中了
        //再嘗試獲取一下提陶,如果獲取不到烫沙,就先加入
        if (!tryAcquire(arg) &&
                //獨(dú)占模式,添加了一個(gè)隙笆,然后返回當(dāng)前節(jié)點(diǎn)
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){
            //當(dāng)前線程自我中斷
            selfInterrupt();
        }
    }

tryAcquire方法最后會(huì)調(diào)用ReetrantLock的Sync的nonfairTryAcquire方法

final boolean nonfairTryAcquire(int acquires) {
            //獲取當(dāng)前線程
            final Thread current = Thread.currentThread();
            //拿到當(dāng)前鎖的state
            int c = getState();
            //如果是0的話锌蓄,就把a(bǔ)qs的state設(shè)置為acquires,當(dāng)前就可以拿到鎖了
            if (c == 0) {
                //嘗試一下cas撑柔,如果成功就可以拿到鎖了
                if (compareAndSetState(0, acquires)) {
                    //設(shè)置當(dāng)前線程為當(dāng)前l(fā)ock所擁有的鎖
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //如果當(dāng)前的鎖就是被這個(gè)線程拿到
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                //那么就是設(shè)置可重入狀態(tài)了瘸爽,這個(gè)要加
                setState(nextc);
                return true;
            }
            //否則當(dāng)前線程無(wú)法獲取
            return false;
        }

其中addWaiter方法

/**
     * Creates and enqueues node for current thread and given mode.
     * 就是當(dāng)前線程沒(méi)有拿到鎖的時(shí)候
     * 1.如果尾部節(jié)點(diǎn)有值,那么加到最后一個(gè)返回
     * 2.如果尾部節(jié)點(diǎn)沒(méi)有值铅忿,添加一個(gè)節(jié)點(diǎn)剪决,然后返回
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    private Node addWaiter(Node mode) {
        /**
         * 當(dāng)前線程構(gòu)建一個(gè)node,是獨(dú)占模式的
         * new 出來(lái)的這個(gè)節(jié)點(diǎn)的結(jié)構(gòu)是
         * node(當(dāng)前線程檀训,nextWaiter是個(gè)mode)
         */
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        //如果尾節(jié)點(diǎn)不為空
        if (pred != null) {
            //將當(dāng)前節(jié)點(diǎn)的前驅(qū)指向尾部節(jié)點(diǎn)
            node.prev = pred;
            //將當(dāng)前節(jié)點(diǎn)設(shè)置為尾部節(jié)點(diǎn)柑潦,使用cas設(shè)置一下
            if (compareAndSetTail(pred, node)) {
                //現(xiàn)在的尾部借點(diǎn)就是 node了,然后再將pred的next指向尾部峻凫,然后返回
                pred.next = node;
                return node;
            }
        }
        //如果尾部節(jié)點(diǎn)是空的渗鬼,就建立一節(jié)點(diǎn),頭和尾都指向這個(gè)節(jié)點(diǎn)荧琼,而且自己指向自己[自己的pre指向自己譬胎,自己的next指向自己]
        enq(node);
        return node;
    }

private Node enq(final Node node) {
        //自旋操作
        for (;;) {
            //線程A:第一次的時(shí)候 tail是null,需要初始化
            //線程A:第二次進(jìn)來(lái)的時(shí)候命锄,由于是自旋 此時(shí)t=head=tail
            Node t = tail;
            if (t == null) { // Must initialize 必須進(jìn)行初始化
                //尾巴節(jié)點(diǎn)是空的堰乔,先初始化一下head節(jié)點(diǎn),再將head節(jié)點(diǎn)給tail節(jié)點(diǎn)
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                //線程A:第二次進(jìn)來(lái)的時(shí)候累舷,由于是自旋浩考,
                //當(dāng)前節(jié)點(diǎn)的前驅(qū)是t,有可能自己指向了自己
                node.prev = t;
                //這一步相當(dāng)于把tail的引用指向了新增的node
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

執(zhí)行如圖


image.png

最后重點(diǎn)的自旋獲取鎖的方法acquireQueued

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末被盈,一起剝皮案震驚了整個(gè)濱河市析孽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌只怎,老刑警劉巖袜瞬,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異身堡,居然都是意外死亡邓尤,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門贴谎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)汞扎,“玉大人,你說(shuō)我怎么就攤上這事擅这〕浩牵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵仲翎,是天一觀的道長(zhǎng)痹扇。 經(jīng)常有香客問(wèn)我,道長(zhǎng)溯香,這世上最難降的妖魔是什么鲫构? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮玫坛,結(jié)果婚禮上结笨,老公的妹妹穿的比我還像新娘。我一直安慰自己湿镀,他們只是感情好禀梳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著肠骆,像睡著了一般算途。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蚀腿,一...
    開(kāi)封第一講書(shū)人閱讀 51,258評(píng)論 1 300
  • 那天嘴瓤,我揣著相機(jī)與錄音,去河邊找鬼莉钙。 笑死廓脆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的磁玉。 我是一名探鬼主播停忿,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蚊伞!你這毒婦竟也來(lái)了席赂?” 一聲冷哼從身側(cè)響起吮铭,我...
    開(kāi)封第一講書(shū)人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎颅停,沒(méi)想到半個(gè)月后谓晌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡癞揉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年纸肉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喊熟。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柏肪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芥牌,到底是詐尸還是另有隱情烦味,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布胳泉,位于F島的核電站拐叉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏扇商。R本人自食惡果不足惜凤瘦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望案铺。 院中可真熱鬧蔬芥,春花似錦、人聲如沸控汉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)姑子。三九已至乎婿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間街佑,已是汗流浹背谢翎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沐旨,地道東北人森逮。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像磁携,于是被迫代替她去往敵國(guó)和親褒侧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容