日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
synchronized原理是什么

本篇內(nèi)容介紹了“synchronized原理是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

成都創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比那坡網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式那坡網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋那坡地區(qū)。費(fèi)用合理售后完善,十余年實(shí)體公司更值得信賴。

(一)概述

在多線程的程序執(zhí)行中,有可能會(huì)出現(xiàn)多個(gè)線程會(huì)同時(shí)訪問(wèn)一個(gè)共享并且可變資源的情況,這種時(shí)候由于線程的執(zhí)行是不可控的,所以必須采用一些方式來(lái)控制該資源的訪問(wèn),這種方式就是“加鎖”。

我們把那些可能會(huì)被多個(gè)線程同時(shí)操作的資源稱為臨界資源,加鎖的目的就是讓這些臨界資源在同一時(shí)刻只能有一個(gè)線程可以訪問(wèn)。

(二)CAS的介紹

CAS:compare and swap,比較且交換。使用CAS操作可以在沒(méi)有鎖的情況下完成多線程對(duì)一個(gè)值的更新。CAS的具體操作如下:

當(dāng)要更新一個(gè)值時(shí),先獲取當(dāng)前值E,計(jì)算更新后的結(jié)果值V(先不更新),當(dāng)要去更新這個(gè)值時(shí),比較此時(shí)這個(gè)值是否還是等于E,如果相等,則將E更新為V,如果不相等,則重新進(jìn)行上面的操作。

以i++操作為例,在沒(méi)有鎖的情況下,這個(gè)操作是線程不安全的,假設(shè)i的初始值為0,CAS操作先獲取原值E=0,計(jì)算更新后的值V=1,要更新之前先比較這個(gè)值是否還是等于0,如果等于0則將E更新為1,如果不等于0則說(shuō)明有線程已經(jīng)更新了,重新獲取E值=1,繼續(xù)執(zhí)行。

ABA問(wèn)題

CAS操作可能會(huì)出現(xiàn)ABA問(wèn)題,ABA問(wèn)題即我們要去比較的這個(gè)值E,經(jīng)過(guò)多個(gè)線程的操作后從0變成1又變成了0。此時(shí)雖然E值和更新前相等,但是還是已經(jīng)被更新了。

ABA問(wèn)題的解決辦法

對(duì)E值增加一個(gè)版本號(hào),每次要獲取數(shù)據(jù)時(shí)將版本號(hào)也獲取,每次更新完數(shù)據(jù)之后將版本號(hào)遞增,這樣就算值相等通過(guò)版本號(hào)也能知道是否經(jīng)過(guò)修改。

java在很多地方都用到了CAS操作,比如Atomic的一些類:

AtomicInteger i=new AtomicInteger();

進(jìn)入AtomicInteger方法中,可以看到有個(gè)叫Unsafe的類,進(jìn)入這個(gè)類中,可以看到CAS的幾個(gè)操作方法

synchronized原理是什么

(三)對(duì)象在內(nèi)存中的存儲(chǔ)布局

要想學(xué)會(huì)synchronized,首先要理解Java對(duì)象的內(nèi)存布局,或者稱為內(nèi)存結(jié)構(gòu)。

synchronized原理是什么

一個(gè)對(duì)象分為對(duì)象頭、實(shí)例數(shù)據(jù)和對(duì)其填充。

其中對(duì)象頭Header占12個(gè)字節(jié):Mark Word占8個(gè)字節(jié),類型指針class pointer占4個(gè)字節(jié)(默認(rèn)經(jīng)過(guò)了壓縮,如果不開啟壓縮占8個(gè)字節(jié))

實(shí)例對(duì)象按實(shí)際存儲(chǔ)有不同大小,對(duì)象為空時(shí)等于0。

Padding表示對(duì)齊,當(dāng)此時(shí)內(nèi)存所占字節(jié)不能被8整除時(shí)補(bǔ)上相應(yīng)字節(jié)數(shù)。

以O(shè)bject o=new Object()為例,我們先導(dǎo)入一個(gè)jol依賴,通過(guò)jol可以看到具體的內(nèi)存布局


    org.openjdk.jol
    jol-core
    0.9

運(yùn)行以下代碼:

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

觀察結(jié)果,OFFSET表示偏移量的起始點(diǎn),SIZE表示所占字節(jié),前兩行是Mark Word一共占8個(gè)字節(jié),第三行是class pointer占4個(gè)字節(jié),此時(shí)對(duì)象為空,實(shí)例對(duì)象等于0,最后padding補(bǔ)齊,一共16個(gè)字節(jié)。

synchronized原理是什么

(三)synchronized

synchronized可以保證在同一時(shí)刻,只有一個(gè)線程可以執(zhí)行某個(gè)方法或某個(gè)代碼塊,synchronized把鎖信息存放在對(duì)象頭的MarkWord中。

synchronized作用在非靜態(tài)方法上是對(duì)方法的加鎖,synchronized作用在靜態(tài)方法上是對(duì)當(dāng)前的類加鎖。

在早期的jdk版本中,synchronized是一個(gè)重量級(jí)鎖,保證線程的安全但是效率很低。后來(lái)對(duì)synchronized進(jìn)行了優(yōu)化,有了一個(gè)鎖升級(jí)的過(guò)程

無(wú)鎖態(tài)(new)-->偏向鎖-->輕量級(jí)鎖(自旋鎖)-->重量級(jí)鎖

通過(guò)MarkWord中的8個(gè)字節(jié)也就是64位來(lái)記錄鎖信息。也有人將自旋鎖稱為無(wú)鎖,因?yàn)樽赃x操作并沒(méi)有給一個(gè)對(duì)象上鎖,這里只要理解意思即可。

synchronized原理是什么

3.1 鎖升級(jí)過(guò)程詳解:

當(dāng)給一個(gè)對(duì)象增加synchronized鎖之后,相當(dāng)于上了一個(gè)偏向鎖。

當(dāng)有一個(gè)線程去請(qǐng)求時(shí),就把這個(gè)對(duì)象MarkWord的ID改為當(dāng)前線程指針I(yè)D(JavaThread),只允許這一個(gè)線程去請(qǐng)求對(duì)象。

當(dāng)有其他線程也去請(qǐng)求時(shí),就把鎖升級(jí)為輕量級(jí)鎖。每個(gè)線程在自己的線程棧中生成LockRecord,用CAS自旋操作將請(qǐng)求對(duì)象MarkWordID改為自己的LockRecord,成功的線程請(qǐng)求到了該對(duì)象,未成功的對(duì)象繼續(xù)自旋。

如果競(jìng)爭(zhēng)加劇,當(dāng)有線程自旋超過(guò)一定次數(shù)時(shí)(在JDK1.6之后,這個(gè)自旋次數(shù)由JVM自己控制),就將輕量級(jí)鎖升級(jí)為重量級(jí)鎖,線程掛起,進(jìn)入等待隊(duì)列,等待操作系統(tǒng)的調(diào)度。

3.2 加鎖的字節(jié)碼實(shí)現(xiàn)

synchronized關(guān)鍵字被編譯成字節(jié)碼之后會(huì)被翻譯成monitorenter和monitorexit兩條指令,進(jìn)入同步代碼塊時(shí)執(zhí)行monitorenter,同步代碼塊執(zhí)行完畢后執(zhí)行monitorexit

(四)鎖消除

在某些情況下,如果JVM認(rèn)為不需要鎖,會(huì)自動(dòng)消除鎖,比如下面這段代碼:

public void add(String a,String b){
    StringBuffer sb=new StringBuffer();
    sb.append(a).append(b);
}

StringBuffer是線程安全的,但是在這個(gè)add方法中stringbuffer是不能共享的資源,因此加鎖只會(huì)徒增性能消耗,JVM就會(huì)消除StringBuffer內(nèi)部的鎖。

(五)鎖粗化

在某些情況下,JVM檢測(cè)到一連串的操作都在對(duì)同一個(gè)對(duì)象不斷加鎖,就會(huì)將這個(gè)鎖加到這一連串操作的外部,比如:

StringBuffer sb=new StringBuffer();
while(i<100){
    sb.append(str);
    i++;
}

上述操作StringBuffer每次添加數(shù)據(jù)都要加鎖和解鎖,連續(xù)100次,這時(shí)候JVM就會(huì)將鎖加到更外層(while)部分。

(六)逃逸分析

首先問(wèn)一個(gè)經(jīng)?;A(chǔ)的虛擬機(jī)問(wèn)題,實(shí)例對(duì)象存放在虛擬機(jī)的哪個(gè)位置?按以前的回答,示例對(duì)象放在堆上,引用放在棧上,示例的元數(shù)據(jù)等存放在方法區(qū)或者元空間。

但這是有前提的,前提是示例對(duì)象沒(méi)有線程逃逸行為。

JDK1.7開始默認(rèn)開啟了逃逸分析,所謂逃逸分析,就是指如果一個(gè)對(duì)象被編譯器發(fā)現(xiàn)只能被一個(gè)線程訪問(wèn),那么這個(gè)對(duì)象就不需要考慮同步。JVM就對(duì)這種對(duì)象進(jìn)行優(yōu)化,將堆分配轉(zhuǎn)化為棧分配,歸根結(jié)底就是虛擬機(jī)在編譯過(guò)程中對(duì)程序的一種優(yōu)化行為。

開啟逃逸分析:- XX:+DoEscapeAnalysis
關(guān)閉逃逸分析: -XX:--DoEscapeAnalysis

“synchronized原理是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!


本文名稱:synchronized原理是什么
URL標(biāo)題:http://www.dlmjj.cn/article/jhohso.html