久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

Java中synchronized鎖升級的過程

本文主要介紹了Java中synchronized鎖升級的過程,synchronized相對于早期的synchronized做出了優(yōu)化,從以前的加鎖就是重量級鎖優(yōu)化成了有一個鎖升級的過,下文詳細內(nèi)容需要的小伙伴可以參考

簡介

在多線程中解決線程安全的問題時常用到Synchronized,現(xiàn)在的synchronized相對于早期的synchronized做出了優(yōu)化,從以前的加鎖就是重量級鎖優(yōu)化成了有一個鎖升級的過程(偏向鎖->輕量級鎖->重量級鎖)。

CAS

cas的全稱是compare and swap,從名稱上可以看出它是先比較再進行設置,它是一種在多線程環(huán)境下實現(xiàn)同步功能的機制。

下面這段代碼是在ReentrantLock類中復制的一段關(guān)于CAS操作的代碼

protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

compareAndSwapInt的參數(shù),這里的參數(shù)一和參數(shù)二現(xiàn)在把他理解成是一個參數(shù)unsafe.compareAndSwapInt(curr, expect, update);所以這一個Cas操作里面需要三個參數(shù)

  • 參數(shù)一:當前值
  • 參數(shù)二:期望值
  • 參數(shù)三:需要修改成的值

只有在當前值和期望值一致的時候才會將當前值修改成參數(shù)三所傳入的值。

CAS在JUC包中應用很廣泛,比如在AtomicXXX類中使用到了大量的CAS操作,

CAS不是很難理解,有個概念就好。

markWord

如果了解對象的內(nèi)存布局的可以略過此段。這個對象的內(nèi)存布局是和JVM的實現(xiàn)有關(guān),本章所說的是HotSpot的實現(xiàn)。

當一個對象被創(chuàng)建出來后它在內(nèi)存中的布局如下,由四部分組成:

  • 8個字節(jié)的markword,(markword里面包含了其它的東西,比如GC標記,鎖類型)
  • 4個字節(jié)的ClassPoint(此指針指向的Class),默認是開啟指針壓縮所以是四個字節(jié),關(guān)閉指針壓縮后是八個字節(jié)
  • 實例對象中的成員屬性大小
  • 字節(jié)填充(有的JVM需要8字節(jié)對齊,如果上面的字節(jié)相加后不能被8整除,則需要在此補齊)

看到上面的圖,應該可以大概的看出來synchronized加鎖,其實就是修改的對像頭里面的markword的數(shù)據(jù)。所以synchronized可以對任何一個對象加鎖

現(xiàn)在有一個Java類T,將它new出來之后它的對象的內(nèi)存布局是什么樣子的呢?

class T{
    Integer age;
}

可以通過一個小工具來查看下這個T類在內(nèi)存中的對象布局

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
    <scope>compile</scope>
</dependency>

通過下面的程序來打印下T對象的布局是什么樣子的。

public static void main(String[] args) {
    T o = new T();
    System.out.println(ClassLayout.parseInstance(o).toPrintable());
}

這張圖是一個沒有加鎖的對象的對象布局。

通過synchronized后的對象布局是什么樣子的呢?這次再修改下T類,目的是讓它存在字節(jié)填充

class T{
    Integer age;
    Integer age1;
}
public static void main(String[] args) {
    T o = new T();
    synchronized (o){
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
}

到這里可能有些小伙伴有疑問,這里為啥是輕量級鎖,不應該先是偏向鎖嗎?原因如下:

因為偏向鎖是有4秒的延遲的,所以如果想要看到效果可以在代碼里加上sleep(4100)就可以了。或者是通過jvm參數(shù)-XX:BiasedLockingStartupDelay=0將延遲設置成0

看完這里也對markword有了些了解了,因為在synchronized中加鎖就是通過cas的方式修改的markword中的鎖狀態(tài)

Synchronized的鎖升級

上圖大概就是Synchronized加鎖后的一個鎖升級的過程。從早期的重量級鎖優(yōu)化到了現(xiàn)在一個輕量級鎖。

偏向鎖

上面的重量級鎖說到重量級鎖想要申請一把鎖需要用戶態(tài)到內(nèi)核態(tài)的一個轉(zhuǎn)換,到了后期的JDK版本中,加鎖不用在去向OS去申請鎖了,只需要在用戶態(tài)就可以完成加鎖。

從名字上可以看出偏向鎖它就是偏向某一個線程,把這個鎖加到這個線程上,在加鎖的時候如果發(fā)現(xiàn)當前鎖的競爭線程只有一個線程的話,那么這個鎖直接偏向這個線程。直接上鎖,不存在競爭。并在線程棧中創(chuàng)建一個LR(鎖記錄)并將markword拷貝到LR中,同時鎖中的markwrod中的指針也會指向當前持有鎖線程的LR

這里的LR是有什么作用?

首先synchronized是一個可重入鎖,它即然是一個可重入鎖它就得有一個東西用來記錄重入的次數(shù)(加鎖幾次必須解鎖幾次)。在解鎖時LR在棧中彈出一個就表示解鎖一次。

當有多個線程競爭的時候會升級成輕量級鎖(自旋鎖)

通過下圖來看下偏向鎖是怎么一回事。

當大呆需要上WC時,只有它自已要上WC,此時并沒有其它的人需要上WC,那么這時這個WC可以直接給大呆使用,并且大呆把可以標識自已身份的ID貼到門上,表示此時大呆占用了這個WC。

當又有一個線程來搶占鎖時發(fā)現(xiàn)當前鎖已被占用,此時鎖會從偏向鎖升級成輕量級鎖。

匿名偏向

在執(zhí)行的時候?qū)⑵蜴i的延遲設置成0-XX:BiasedLockingStartupDelay=0

 public static void main(String[] args) throws InterruptedException {
     T o = new T();
     System.out.println(ClassLayout.parseInstance(o).toPrintable());
 }

可以看這個程序的執(zhí)行結(jié)果,當前的鎖狀態(tài)是偏向鎖,而有意思是的鎖存在,但是他并沒有指向線程的指針,

這種情況稱為匿名偏向。

輕量級鎖

說到輕量級鎖可能需要在兩種情況下來說它,一是在升級成輕量鎖之前有偏向鎖,另一種是在升級輕量鎖之前沒有偏向鎖,這里說完第一種第二種不用解釋各位也會明白是怎么一回事。

還是用上面這個圖來解釋,此時當前的WC被大呆所占用,這時二呆來了也要使用WC。這時大呆和二呆就要通過CAS的方式來搶占WC。

因為此時鎖的狀態(tài)是偏向鎖的狀態(tài),二呆來了也要使用WC(這時有兩個人同時要使用WC,這時就要將偏向鎖升級成輕量級鎖),在升級輕量鎖之前首先需要將WC上的標識大呆身份的ID撕下來(這一步叫做偏向鎖的撤銷),然后能過自旋+CAS的方式兩個人來搶鎖。當其中一個線程搶鎖成功后,會將LR貼到WC的門上,表示W(wǎng)C當前被某個線程占用,然后另一個沒有搶到鎖的線程就一直自旋,當自旋一定次數(shù)后升級成重量級鎖。

如果在升級輕量鎖之前沒有偏向鎖,此時兩個線程直接自旋+CAS的方式來搶鎖。

重量級鎖

在了解重量級鎖之前,我想應該先說下用戶態(tài)與內(nèi)核態(tài)

對于系統(tǒng)而言,它可以做的一些事情,普通的應用程序是無法完成的,比如系統(tǒng)可以干掉硬盤,如果普通的程序想要干掉硬盤它必須向操作系統(tǒng)去申請,由此操作系統(tǒng)中的指令分了級別,操作系統(tǒng)級別可以訪問所有的指令,在用戶態(tài)下只能訪問用戶能訪問的指令,如果用戶態(tài)要訪問內(nèi)核態(tài)可以執(zhí)行的指令必須去向操作系統(tǒng)去申請,請操作系統(tǒng)調(diào)用。

在JDK早期,上鎖只能上重量級鎖。因為,所謂的JVM其實它也是工作在用戶態(tài)的一個進程,如果想要對一個對象進行上鎖,那它必須去向系統(tǒng)去申請鎖。申請鎖成功后,還需要將這把鎖從內(nèi)核態(tài)返回到用戶態(tài),它稱為重量級鎖的原因就是在鎖申請的時候都要有一個在用戶態(tài)到內(nèi)核態(tài)的轉(zhuǎn)換

當搶占到鎖后,markword里面記錄的不再是LR的指針,而是指向的是一個C++的對象ObjectMonitor,

如果當前線程自旋一段時間后沒有搶到鎖就會升級成重量級鎖,并將當前的線程存入EntryList隊列中阻塞,持有鎖的線程執(zhí)行完成后,在喚醒EntryList隊列中的線程去搶占鎖。

總結(jié)

synchronized的鎖升級過程:

  • 偏向鎖未啟動,創(chuàng)建出來的是普通對象, 如果有一個線程來搶占鎖,該鎖偏向此線程,這時升級為偏向鎖。
    • 在偏向鎖的基礎上又來一個線程搶占鎖此時升級為輕量級鎖。當一個線程沒有搶占到鎖,并且自旋了一定時間后還沒有搶到鎖,就會升級成重量級鎖。
  • 在偏向鎖的基礎上如果出現(xiàn)了重度競爭就會直接升級成重量級鎖
  • 偏向鎖已啟動,創(chuàng)建出來的對象匿名偏向,后面的鎖升級和上面寫的一樣。

到此這篇關(guān)于Java中synchronized鎖升級的過程的文章就介紹到這了,更多相關(guān)synchronized鎖升級內(nèi)容請搜索html5模板網(wǎng)以前的文章希望大家以后多多支持html5模板網(wǎng)!

【網(wǎng)站聲明】本站部分內(nèi)容來源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問題,如果有圖片或者內(nèi)容侵犯了您的權(quán)益,請聯(lián)系我們刪除處理,感謝您的支持!

相關(guān)文檔推薦

主站蜘蛛池模板: 麻豆视频在线看 | 中文字幕在线观看一区二区 | 一区二区三区在线免费观看视频 | 中文字幕久久精品 | 欧美日韩视频一区二区 | 天天看天天干 | 精品国产91| av免费网站在线 | 91视频中文 | 国产精品亚洲欧美日韩一区在线 | 青青草在线播放 | 亚洲国产精品成人 | 蜜桃久久 | 99精品亚洲国产精品久久不卡 | 国产999在线观看 | 亚洲欧美激情精品一区二区 | 亚洲狠狠爱 | 观看av | 黄色毛片免费看 | 久久91av| 久久综合九色综合欧美狠狠 | k8久久久一区二区三区 | 古装三级在线播放 | 国产精品揄拍一区二区 | 亚洲精品视频免费观看 | 日本久草视频 | 蜜臀久久| 综合成人在线 | a在线视频| 日韩在线小视频 | 欧美日本亚洲 | 国产美女视频黄 | 亚洲最大的成人网 | 日中文字幕在线 | 日韩欧美一区二区三区免费观看 | 91精品国产综合久久久久久丝袜 | 老司机深夜福利网站 | 国产一区二区三区在线 | 亚洲 欧美 日韩在线 | 久久久久久亚洲精品 | 18gay男同69亚洲网站 |