成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Synchronized的原理介紹

本篇內(nèi)容主要講解“Synchronized的原理介紹”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Synchronized的原理介紹”吧!

創(chuàng)新互聯(lián)建站是一家專(zhuān)業(yè)提供樂(lè)業(yè)企業(yè)網(wǎng)站建設(shè),專(zhuān)注與成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、H5開(kāi)發(fā)、小程序制作等業(yè)務(wù)。10年已為樂(lè)業(yè)眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專(zhuān)業(yè)的建站公司優(yōu)惠進(jìn)行中。

1. CAS

CAS全稱(chēng):CompareAndSwap,故名思意:比較并交換。他的主要思想就是:**我需要對(duì)一個(gè)值進(jìn)行修改,我不會(huì)直接修改,而是將當(dāng)前我認(rèn)為的值和要修改的值傳入,如果此時(shí)內(nèi)存中的確為我認(rèn)為的值,那么就進(jìn)行修改,否則修改失敗。**他的思想是一種樂(lè)觀鎖的思想。

一張圖解釋他的工作流程:

Synchronized的原理介紹

知道了它的工作原理,我們來(lái)聽(tīng)一個(gè)場(chǎng)景:現(xiàn)在有一個(gè)int類(lèi)型的數(shù)字它等于1,存在三個(gè)線程需要對(duì)其進(jìn)行自增操作。

一般來(lái)說(shuō),我們認(rèn)為的操作步驟是這樣:線程從主內(nèi)存中讀取這個(gè)變量,到自己的工作空間中,然后執(zhí)行變量自增,然后回寫(xiě)主內(nèi)存,但這樣在多線程狀態(tài)下會(huì)存在安全問(wèn)題。而如果我們保證變量的安全性,常用的做法是ThreadLocal或者直接加鎖。(對(duì)ThreadLocal不了解的兄弟,看我這篇文章一文讀懂ThreadLocal設(shè)計(jì)思想)

這個(gè)時(shí)候我們思考一下,如果使用我們上面的CAS進(jìn)行對(duì)值的修改,我們需要如何操作。

首先,我們需要將當(dāng)前線程認(rèn)為的值傳入,然后將想要修改的值傳入。如果此時(shí)內(nèi)存中的值和我們的期望值相等,進(jìn)行修改,否則修改失敗。這樣是不是解決了一個(gè)多線程修改的問(wèn)題,而且它沒(méi)有使用到操作系統(tǒng)提供的鎖。

上面的流程其實(shí)就是類(lèi)AtomicInteger執(zhí)行自增操作的底層實(shí)現(xiàn),它保證了一個(gè)操作的原子性。我們來(lái)看一下源碼。

public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            //從內(nèi)存中讀取最新值
            var5 = this.getIntVolatile(var1, var2);
            //修改
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
 }

實(shí)現(xiàn)CAS使用到了Unsafe類(lèi),看它的名字就知道不安全,所以JDK不建議我們使用。對(duì)比我們上面多個(gè)線程執(zhí)行一個(gè)變量的修改流程,這個(gè)類(lèi)的操作僅僅增加了一個(gè)自旋,它在不斷獲取內(nèi)存中的最新值,然后執(zhí)行自增操作。

可能有兄弟說(shuō)了,那getIntVolatilecompareAndSwapInt操作如何保證原子性。

對(duì)于getIntVolatile來(lái)說(shuō),讀取內(nèi)存中的地址,本來(lái)就一部操作,原子性顯而易見(jiàn)。

對(duì)于compareAndSwapInt來(lái)說(shuō),它的原子性由CPU保證,通過(guò)一系列的CPU指令實(shí)現(xiàn),其C++底層是依賴(lài)于Atomic::cmpxchg_ptr實(shí)現(xiàn)的

到這里CAS講完了,不過(guò)其中還有一個(gè)ABA問(wèn)題,有興趣可以去了解我的這篇文章多線程知識(shí)點(diǎn)小節(jié)。里面有詳細(xì)的講解。

我們通過(guò)CAS可以保證了操作的原子性,那么我們需要考慮一個(gè)東西,鎖是怎么實(shí)現(xiàn)的。對(duì)比生活中的case,我們通過(guò)一組密碼或者一把鑰匙實(shí)現(xiàn)了一把鎖,同樣在計(jì)算機(jī)中也通過(guò)一個(gè)鑰匙即synchronized代碼塊使用的鎖對(duì)象。

那其他線程如何判斷當(dāng)前資源已經(jīng)被占有了呢?

在計(jì)算機(jī)中的實(shí)現(xiàn),往往是通過(guò)對(duì)一個(gè)變量的判斷來(lái)實(shí)現(xiàn),無(wú)鎖狀態(tài)為0,有鎖狀態(tài)為1等等來(lái)判斷這個(gè)資源是否被加鎖了,當(dāng)一個(gè)線程釋放鎖時(shí)僅僅需要將這個(gè)變量值更改為0,代表無(wú)鎖。

我們僅僅需要保證在進(jìn)行變量修改時(shí)的原子性即可,而剛剛的CAS剛好可以解決這個(gè)問(wèn)題

至于那個(gè)鎖變量存儲(chǔ)在哪里這個(gè)問(wèn)題,就是下面的內(nèi)容了,對(duì)象的內(nèi)存布局

2. 內(nèi)存布局

各位兄弟們,應(yīng)該都清楚,我們創(chuàng)建的對(duì)象都是被存放到堆中的,最后我們獲得到的是一個(gè)對(duì)象的引用指針。那么有一個(gè)問(wèn)題就會(huì)誕生了,JVM創(chuàng)建的對(duì)象的時(shí)候,開(kāi)辟了一塊空間,那這個(gè)空間里都有什么東西?這個(gè)就是我們這個(gè)點(diǎn)的內(nèi)容。

先來(lái)結(jié)論:Java中存在兩種類(lèi)型的對(duì)象,一種是普通對(duì)象,另一種是數(shù)組

對(duì)象內(nèi)存布局

Synchronized的原理介紹

我們來(lái)一個(gè)一個(gè)解釋其含義。

**白話版:**對(duì)象頭中包含又兩個(gè)字段,Mark Word主要存儲(chǔ)改對(duì)象的鎖信息,GC信息等等(鎖升級(jí)的實(shí)現(xiàn))。而其中的Klass Point代表的是一個(gè)類(lèi)指針,它指向了方法區(qū)中類(lèi)的定義和結(jié)構(gòu)信息。而Instance Data代表的就是類(lèi)的成員變量。在我們剛剛學(xué)習(xí)Java基礎(chǔ)的時(shí)候,都聽(tīng)過(guò)老師講過(guò),對(duì)象的非靜態(tài)成員屬性都會(huì)被存放在堆中,這個(gè)就是對(duì)象的Instance Data。相對(duì)于對(duì)象而言,數(shù)組額外添加了一個(gè)數(shù)組長(zhǎng)度的屬性

最后一個(gè)對(duì)其數(shù)據(jù)是什么?

我們拿一個(gè)場(chǎng)景來(lái)展示這個(gè)原因:**想像一下,你和女朋友周末打算出去玩,女朋友讓你給她帶上口紅,那么這個(gè)時(shí)候你僅僅會(huì)帶上口紅嘛?當(dāng)然不是,而是將所有的必用品統(tǒng)統(tǒng)帶上,以防剛一出門(mén)就得回家拿東西?。?!**這種行為叫啥?未雨綢繆,沒(méi)錯(cuò),暖男行為。還不懂?再來(lái)一個(gè)案例。你準(zhǔn)備創(chuàng)業(yè)了,資金非常充足,你需要注冊(cè)一個(gè)域名,你僅僅注冊(cè)一個(gè)嘛?不,而是將所有相關(guān)的都注冊(cè)了,防止以后大價(jià)錢(qián)買(mǎi)域名。一個(gè)道理。

而對(duì)于CPU而言,它在進(jìn)行計(jì)算處理數(shù)據(jù)的時(shí)候,不可能需要什么拿什么吧,那對(duì)其性能損耗非常嚴(yán)重。所以有一個(gè)協(xié)議,CPU在讀取數(shù)據(jù)的時(shí)候,不僅僅只拿需要的數(shù)據(jù),而是獲取一行的數(shù)據(jù),這就是緩存行,而一行是64個(gè)字節(jié)

所以呢?通過(guò)這個(gè)特性可以玩一些詭異的花樣,比如下面的代碼。

public class CacheLine {
    private volatile Long l1 , l2;
}

我們給一個(gè)場(chǎng)景:兩個(gè)線程t1和t2分別操作l1l2,那么當(dāng)t1對(duì)l1做了修改以后,l2需不需要重新讀取主內(nèi)存種值。答案是一定,根據(jù)我們上面對(duì)于緩存行的理解,l1和l2必然位于同一個(gè)緩存行中,根據(jù)緩存一致性協(xié)議,當(dāng)數(shù)據(jù)被修改以后,其他CPU需要重新重主內(nèi)存中讀取數(shù)據(jù)。這就引發(fā)了偽共享的問(wèn)題

那么為什么對(duì)象頭要求會(huì)存在一個(gè)對(duì)其數(shù)據(jù)呢?

HotSpot虛擬機(jī)要求每一個(gè)對(duì)象的內(nèi)存大小必須保證為8字節(jié)的整數(shù)倍,所以對(duì)于不是8字節(jié)的進(jìn)行了對(duì)其補(bǔ)充。其原因也是因?yàn)榫彺嫘械脑?/p>

對(duì)象=對(duì)象頭+實(shí)例數(shù)據(jù)

3. 無(wú)鎖

我們?cè)谇懊媪牧艘幌?,?jì)算機(jī)中的鎖的實(shí)現(xiàn)思路和對(duì)象在內(nèi)存中的布局,接下來(lái)我們來(lái)聊一下它的具體鎖實(shí)現(xiàn),為對(duì)象加鎖使用的是對(duì)象內(nèi)存模型中的對(duì)象頭,通過(guò)對(duì)其鎖標(biāo)志位和偏向鎖標(biāo)志位的修改實(shí)現(xiàn)對(duì)資源的獨(dú)占即加鎖操作。接下來(lái)我們看一下它的內(nèi)存結(jié)構(gòu)圖。

Synchronized的原理介紹

上圖就是對(duì)象頭在內(nèi)存中的表現(xiàn)(64位),JVM通過(guò)對(duì)對(duì)象頭中的鎖標(biāo)志位和偏向鎖位的修改實(shí)現(xiàn)“無(wú)鎖”。

對(duì)于無(wú)鎖這個(gè)概念來(lái)說(shuō),在1.6之前,即所有的對(duì)象,被創(chuàng)建了以后都處于無(wú)鎖狀態(tài),而在1.6之后,偏向鎖被開(kāi)啟,對(duì)象在經(jīng)歷過(guò)幾秒的時(shí)候(4~5s)以后,自動(dòng)升級(jí)為當(dāng)前線程的偏向鎖。(無(wú)論經(jīng)沒(méi)經(jīng)過(guò)synchronized)。

我們來(lái)驗(yàn)證一下,通過(guò)jol-core工具打印其內(nèi)存布局。注:該工具打印出來(lái)的數(shù)據(jù)信息是反的,即最后幾位在前面,通過(guò)下面的案例可以看到

場(chǎng)景:創(chuàng)建兩個(gè)對(duì)象,一個(gè)在剛開(kāi)始的時(shí)候就創(chuàng)建,另一個(gè)在5秒之后創(chuàng)建,進(jìn)行對(duì)比其內(nèi)存布局

Object object = new Object();
System.out.println(ClassLayout.parseInstance(object).toPrintable());//此時(shí)處于無(wú)鎖態(tài)
try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}
Object o = new Object();
System.out.println("偏向鎖開(kāi)啟");
System.out.println(ClassLayout.parseInstance(o).toPrintable());//五秒以后偏向鎖開(kāi)啟

Synchronized的原理介紹

我們可以看到,線程已開(kāi)啟創(chuàng)建的對(duì)象處于無(wú)鎖態(tài),而在5秒以后創(chuàng)建的線程處于偏向鎖狀態(tài)。

同樣,當(dāng)我們遇到synchronized塊的時(shí)候,也會(huì)自動(dòng)升級(jí)為偏向鎖,而不是和操作系統(tǒng)申請(qǐng)鎖。

說(shuō)完這個(gè),提一嘴一個(gè)面試題吧。解釋一下什么是無(wú)鎖。

從對(duì)象內(nèi)存結(jié)構(gòu)的角度來(lái)說(shuō),是一個(gè)鎖標(biāo)志位的體現(xiàn);從其語(yǔ)義來(lái)說(shuō),無(wú)鎖這個(gè)比較抽象了,因?yàn)樵谝郧版i的概念往往是與操作系統(tǒng)的鎖息息相關(guān),所以新出現(xiàn)的基于CAS的偏向鎖,輕量級(jí)鎖等等也被成為無(wú)鎖。而在synchronized升級(jí)的起點(diǎn)----無(wú)鎖。這個(gè)東西就比較難以解釋?zhuān)荒苷f(shuō)它沒(méi)加鎖。不過(guò)面試的過(guò)程中從對(duì)象內(nèi)存模型中理解可能會(huì)更加舒服一點(diǎn)。

4. 偏向鎖

在實(shí)際開(kāi)發(fā)中,往往資源的競(jìng)爭(zhēng)比較少,于是出現(xiàn)了偏向鎖,故名思意,當(dāng)前資源偏向于該線程,認(rèn)為將來(lái)的一切操作均來(lái)自于改線程。下面我們從對(duì)象的內(nèi)存布局下看看偏向鎖

對(duì)象頭描述:偏向鎖標(biāo)志位通過(guò)CAS修改為1,并且存儲(chǔ)該線程的線程指針

Synchronized的原理介紹

當(dāng)發(fā)生了鎖競(jìng)爭(zhēng),其實(shí)也不算鎖競(jìng)爭(zhēng),就是當(dāng)這個(gè)資源被多個(gè)線程使用的時(shí)候,偏向鎖就會(huì)升級(jí)。

在升級(jí)的期間有一個(gè)點(diǎn)-----全局安全點(diǎn),只有處在這個(gè)點(diǎn)的時(shí)候,才會(huì)撤銷(xiāo)偏向鎖。

全局安全點(diǎn)-----類(lèi)似于CMSstop the world,保證這個(gè)時(shí)候沒(méi)有任何線程在操作這個(gè)資源,這個(gè)時(shí)間點(diǎn)就叫做全局安全點(diǎn)。

可以通過(guò)XX:BiasedLockingStartupDelay=0 關(guān)閉偏向鎖的延遲,使其立即生效。

通過(guò)XX:-UseBiasedLocking=false 關(guān)閉偏向鎖。

5.輕量級(jí)鎖

在聊輕量級(jí)鎖的時(shí)候,我們需要搞明白這幾個(gè)問(wèn)題。什么是輕量級(jí)鎖,什么重量級(jí)鎖?,為什么就重量了,為什么就輕量了?

輕量級(jí)和重量級(jí)的標(biāo)準(zhǔn)是依靠于操作系統(tǒng)作為標(biāo)準(zhǔn)判斷的,在進(jìn)行操作的時(shí)候你有沒(méi)有調(diào)用過(guò)操作系統(tǒng)的鎖資源,如果有就是重量級(jí),如果沒(méi)有就是輕量級(jí)

接下來(lái)我們看一下輕量級(jí)鎖的實(shí)現(xiàn)。

  • 線程獲取鎖,判斷當(dāng)前線程是否處于無(wú)鎖或者偏向鎖的狀態(tài),如果是,通過(guò)CAS復(fù)制當(dāng)前對(duì)象的對(duì)象頭到Lock Recoder放置到當(dāng)前棧幀中(對(duì)于JVM內(nèi)存模型不清楚的兄弟,看這里入門(mén)JVM看這一篇就夠了

  • 通過(guò)CAS將當(dāng)前對(duì)象的對(duì)象頭設(shè)置為棧幀中的Lock Recoder,并且將鎖標(biāo)志位設(shè)置為00

  • 如果修改失敗,則判斷當(dāng)前棧幀中的線程是否為自己,如果是自己直接獲取鎖,如果不是升級(jí)為重量級(jí)鎖,后面的線程阻塞

我們?cè)谏厦嫣岬搅艘粋€(gè)Lock Recoder,這個(gè)東東是用來(lái)保存當(dāng)前對(duì)象的對(duì)象頭中的數(shù)據(jù)的,并且此時(shí)在該對(duì)象的對(duì)象頭中保存的數(shù)據(jù)成為了當(dāng)前Lock Recoder的指針

Synchronized的原理介紹

我們看一個(gè)代碼模擬案例,

public class QingLock {
    public static void main(String[] args) {
        try {
            //睡覺(jué)5秒,開(kāi)啟偏向鎖,可以使用JVM參數(shù)
            TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}
        A o = new A();
        //讓線程交替執(zhí)行
        CountDownLatch countDownLatch = new CountDownLatch(1);
        new Thread(()->{
            o.test();
            countDownLatch.countDown();
        },"1").start();

        new Thread(()->{
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            o.test();
        },"2").start();


    }
}

class A{
    private Object object = new Object();
    public void test(){
        System.out.println("為進(jìn)入同步代碼塊*****");
        System.out.println(ClassLayout.parseInstance(object).toPrintable());
        System.out.println("進(jìn)入同步代碼塊******");
        for (int i = 0; i < 5; i++) {
            synchronized (object){
                System.out.println(ClassLayout.parseInstance(object).toPrintable());
            }
        }
    }
}

運(yùn)行結(jié)果為兩個(gè)線程交替前后

Synchronized的原理介紹

輕量級(jí)鎖強(qiáng)調(diào)的是線程交替使用資源,無(wú)論線程的個(gè)數(shù)有幾個(gè),只要沒(méi)有同時(shí)使用就不會(huì)升級(jí)為重量級(jí)鎖

在上面的關(guān)于輕量級(jí)鎖加鎖步驟的講解中,如果線程CAS修改失敗,則判斷棧幀中的owner是不是自己,如果不是就失敗升級(jí)為重量級(jí)鎖,而在實(shí)際中,JDK加入了一種機(jī)制自旋鎖,即修改失敗以后不會(huì)立即升級(jí)而是進(jìn)行自旋,在JDK1.6之前自旋次數(shù)為10次,而在1.6又做了優(yōu)化,改為了自適應(yīng)自旋鎖,由虛擬機(jī)判斷是否需要進(jìn)行自旋,判斷原因有:當(dāng)前線程之前是否獲取到過(guò)鎖,如果沒(méi)有,則認(rèn)為獲取鎖的幾率不大,直接升級(jí),如果有則進(jìn)行自旋獲取鎖。

6. 重量級(jí)鎖

前面我們談到了無(wú)鎖-->偏向鎖-->輕量級(jí)鎖,現(xiàn)在最后我們來(lái)聊一下重量級(jí)鎖。

這個(gè)鎖在我們開(kāi)發(fā)過(guò)程中很常見(jiàn),線程搶占資源大部分都是同時(shí)的,所以synchronized會(huì)直接升級(jí)為重量級(jí)鎖。我們來(lái)代碼模擬看一下它的對(duì)象頭的狀況。

代碼模擬

public class WeightLock {
    public static void main(String[] args) {
        A a = new A();
        for (int i = 0; i < 2; i++) {
             new Thread(()->{
                a.test();
             },"線程"+ i).start();
        }
    }
}

未進(jìn)入代碼塊之前,兩者均為無(wú)鎖狀態(tài)

Synchronized的原理介紹

開(kāi)始執(zhí)行循環(huán),進(jìn)入代碼塊

Synchronized的原理介紹

在看一眼,對(duì)象頭鎖標(biāo)志位

Synchronized的原理介紹

對(duì)比上圖,可以發(fā)現(xiàn),在線程競(jìng)爭(zhēng)的時(shí)候鎖,已經(jīng)變?yōu)榱酥亓考?jí)鎖。接下來(lái)我們來(lái)看一下重量級(jí)鎖的實(shí)現(xiàn)

6.1 Java匯編碼分析

我們先從Java字節(jié)碼分析synchronzied的底層實(shí)現(xiàn),它的主要實(shí)現(xiàn)邏輯是依賴(lài)于一個(gè)monitor對(duì)象,當(dāng)前線程執(zhí)行遇到monitorenter以后,給當(dāng)前對(duì)象的一個(gè)屬性recursions加一(下面會(huì)詳細(xì)講解),當(dāng)遇到monitorexit以后該屬性減一,代表釋放鎖。

代碼

Object o = new Object();
synchronized (o){

}

匯編碼

Synchronized的原理介紹

上圖就是上面的四行代碼的匯編碼,我們可以看到synchronized的底層是兩個(gè)匯編指令

  • monitoreneter代表synchronized塊開(kāi)始

  • monitorexit代表synchronized塊結(jié)束

有兄弟要說(shuō)了為什么會(huì)有兩個(gè)monitorexit?這也是我曾經(jīng)遇到的一個(gè)面試題

第一個(gè)monitorexit代表了synchronized塊正常退出

第二個(gè)monitorexit代表了synchronized塊異常退出

很好理解,當(dāng)在synchronized塊中出現(xiàn)了異常以后,不能當(dāng)前線程一直拿著鎖不讓其他線程使用吧。所以出現(xiàn)了兩個(gè)monitorexit

同步代碼塊理解了,我們?cè)賮?lái)看一下同步方法。

代碼

public static void main(String[] args) {

}

public synchronized void test01(){

}

匯編碼

Synchronized的原理介紹

我們可以看到,同步方法增加了一個(gè)ACC_SYNCHRONIZED標(biāo)志,它會(huì)在同步方法執(zhí)行之前調(diào)用monitorenter,結(jié)束以后調(diào)用monitorexit指令。

6.2 C++代碼

Java匯編碼的講解中,我們提到了兩個(gè)指令monitorentermonitorexit,其實(shí)他們是來(lái)源于一個(gè)C++對(duì)象monitor,在Java中每創(chuàng)建一個(gè)對(duì)象的時(shí)候都會(huì)有一個(gè)monitor對(duì)象被隱式創(chuàng)建,他們和當(dāng)前對(duì)象綁定,用于監(jiān)視當(dāng)前對(duì)象的狀態(tài)。其實(shí)說(shuō)綁定也不算正確,其實(shí)際流程為:線程本身維護(hù)了兩個(gè)MonitorList列表,分別為空閑(free)和已經(jīng)使用(used),當(dāng)線程遇到同步代碼塊或者同步方法的時(shí)候,會(huì)從空閑列表中申請(qǐng)一個(gè)monitor使用,如果當(dāng)先線程已經(jīng)沒(méi)有空閑的了,則直接從全局(JVM)獲取一個(gè)monitor使用

我們來(lái)看一下C++對(duì)這個(gè)對(duì)象的描述

ObjectMonitor() {
    _header       = NULL;
    _count        = 0;
    _waiters      = 0,
    _recursions   = 0; // 重入次數(shù)
    _object       = NULL; //存儲(chǔ)該Monitor對(duì)象
    _owner        = NULL; //擁有該Monitor對(duì)象的對(duì)象
    _WaitSet      = NULL; //線程等待集合(Waiting)
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ; //多線程競(jìng)爭(zhēng)時(shí)的單向鏈表
    FreeNext      = NULL ;
    _EntryList    = NULL ; //阻塞鏈表(Block)
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
    _previous_owner_tid = 0;
  }

線程加鎖模型

Synchronized的原理介紹

加鎖流程:

  • 最新進(jìn)入的線程會(huì)進(jìn)入_cxp棧中,嘗試獲取鎖,如果當(dāng)前線程獲得鎖就執(zhí)行代碼,如果沒(méi)有獲取到鎖則添加到EntryList阻塞隊(duì)列中

  • 如果在執(zhí)行的過(guò)程的當(dāng)前線程被掛起(wait)則被添加到WaitSet等待隊(duì)列中,等待被喚醒繼續(xù)執(zhí)行

  • 當(dāng)同步代碼塊執(zhí)行完畢以后,從_cxp或者EntryList中獲取一個(gè)線程執(zhí)行

monitorenter加鎖實(shí)現(xiàn)

  • CAS修改當(dāng)前monitor對(duì)象的_owner為當(dāng)前線程,如果修改成功,執(zhí)行操作;

  • 如果修改失敗,判斷_owner對(duì)象是否為當(dāng)前線程,如果是則令_recursions重入次數(shù)加一

  • 如果當(dāng)前實(shí)現(xiàn)是第一次獲取到鎖,則將_recursions設(shè)置為一

  • 等待鎖釋放

阻塞和獲取鎖實(shí)現(xiàn)

  • 將當(dāng)前線程封裝為一個(gè)node節(jié)點(diǎn),狀態(tài)設(shè)置為ObjectWaiter::TS_CXQ

  • 將之添加到_cxp棧中,嘗試獲取鎖,如果獲取失敗,則將當(dāng)前線程掛起,等待喚醒

  • 喚醒以后,從掛起點(diǎn)執(zhí)行剩下的代碼

monitorexit釋放鎖實(shí)現(xiàn)

  • 讓當(dāng)前線程的_recursions重入次數(shù)減一,如果當(dāng)前重入次數(shù)為0,則直接退出,喚醒其他線程

到此,相信大家對(duì)“Synchronized的原理介紹”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!

分享標(biāo)題:Synchronized的原理介紹
轉(zhuǎn)載來(lái)源:http://jinyejixie.com/article48/iiesep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、定制開(kāi)發(fā)、關(guān)鍵詞優(yōu)化、電子商務(wù)、面包屑導(dǎo)航、云服務(wù)器

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁(yè)設(shè)計(jì)
宣威市| 普定县| 商丘市| 常州市| 永和县| 鸡西市| 濮阳县| 莒南县| 通山县| 方城县| 龙南县| 兴隆县| 新源县| 休宁县| 汾西县| 革吉县| 泽库县| 石棉县| 康平县| 城固县| 安图县| 昌宁县| 台东市| 辉县市| 仁布县| 穆棱市| 夹江县| 丰宁| 临邑县| 陕西省| 正镶白旗| 六枝特区| 阜城县| 富阳市| 秭归县| 岑巩县| 思南县| 那曲县| 汕尾市| 天峨县| 胶南市|