日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

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

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
再有人說(shuō)synchronized是重量級(jí)鎖,就把這篇文章扔給他看

?synchronized作為Java程序員最常用同步工具,很多人卻對(duì)它的用法和實(shí)現(xiàn)原理一知半解,以至于還有不少人認(rèn)為synchronized是重量級(jí)鎖,性能較差,盡量少用。

創(chuàng)新互聯(lián)長(zhǎng)期為上千客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為樂(lè)清企業(yè)提供專業(yè)的成都網(wǎng)站建設(shè)、成都做網(wǎng)站,樂(lè)清網(wǎng)站改版等技術(shù)服務(wù)。擁有十多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。

但不可否認(rèn)的是synchronized依然是并發(fā)首選工具,連volatile、CAS、ReentrantLock都無(wú)法動(dòng)搖synchronized的地位。synchronized是工作面試中的必備技能,今天就跟著一燈一塊深入剖析synchronized底層到底做了哪些優(yōu)化?

synchronized是用來(lái)加鎖的,而鎖是加在對(duì)象上面,所以需要先聊一下JVM中對(duì)象構(gòu)成。

1. 對(duì)象的構(gòu)成

Java對(duì)象在JVM內(nèi)存中由三塊區(qū)域組成:對(duì)象頭、實(shí)例數(shù)據(jù)和對(duì)齊填充。

對(duì)象頭又分為:Mark Word(標(biāo)記字段)、Class Pointer(類型指針)、數(shù)組長(zhǎng)度(如果是數(shù)組)。

實(shí)例數(shù)據(jù)是對(duì)象實(shí)際有效信息,包括本類信息和父類信息等。

對(duì)齊填充沒(méi)有特殊含義,由于虛擬機(jī)要求 對(duì)象起始地址必須是8字節(jié)的整數(shù)倍,作用僅是字節(jié)對(duì)齊。

Class Pointer是對(duì)象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例。

重點(diǎn)關(guān)注一下對(duì)象頭中Mark Word,里面存儲(chǔ)了對(duì)象的hashcode、鎖狀態(tài)標(biāo)識(shí)、持有鎖的線程id、GC分代年齡等。

在32為的虛擬機(jī)中,Mark Word的組成如下:

2. synchronized鎖優(yōu)化

從JDK1.6開始,就對(duì)synchronized的實(shí)現(xiàn)機(jī)制進(jìn)行了較大調(diào)整,包括使用JDK1.5引進(jìn)的CAS自旋之外,還增加了自適應(yīng)的CAS自旋、鎖消除、鎖粗化、偏向鎖、輕量級(jí)鎖等優(yōu)化策略。由于使得synchronized性能極大提高,同時(shí)語(yǔ)義清晰、操作簡(jiǎn)單、無(wú)需手動(dòng)關(guān)閉,所以推薦在允許的情況下盡量使用此關(guān)鍵字,同時(shí)在性能上此關(guān)鍵字還有優(yōu)化的空間。

鎖主要存在四種狀態(tài),依次是:無(wú)鎖狀態(tài)、偏向鎖狀態(tài)、輕量級(jí)鎖狀態(tài)、重量級(jí)鎖狀態(tài),性能依次是從高到低。鎖可以從偏向鎖升級(jí)到輕量級(jí)鎖,再升級(jí)的重量級(jí)鎖。但是鎖的升級(jí)是單向的,也就是說(shuō)只能從低到高升級(jí),不會(huì)出現(xiàn)鎖的降級(jí)。

在 JDK 1.6 中默認(rèn)是開啟偏向鎖和輕量級(jí)鎖的,可以通過(guò)-XX:-UseBiasedLocking來(lái)禁用偏向鎖。

2.1 自旋鎖

線程的掛起與恢復(fù)需要CPU從用戶態(tài)轉(zhuǎn)為內(nèi)核態(tài),頻繁的阻塞和喚醒對(duì)CPU來(lái)說(shuō)是一件負(fù)擔(dān)很重的工作,勢(shì)必會(huì)給系統(tǒng)的并發(fā)性能帶來(lái)很大的壓力。同時(shí)我們發(fā)現(xiàn)在許多應(yīng)用上面,對(duì)象鎖的鎖狀態(tài)只會(huì)持續(xù)很短一段時(shí)間,為了這一段很短的時(shí)間頻繁地阻塞和喚醒線程是非常不值得的。

自旋鎖就是指當(dāng)一個(gè)線程嘗試獲取某個(gè)鎖時(shí),如果該鎖已被其他線程占用,就一直循環(huán)檢測(cè)鎖是否被釋放,而不是進(jìn)入線程掛起或睡眠狀態(tài)。

自旋鎖適用于鎖保護(hù)的臨界區(qū)很小的情況,臨界區(qū)很小的話,鎖占用的時(shí)間就很短。自旋等待不能替代阻塞,雖然它可以避免線程切換帶來(lái)的開銷,但是它占用了CPU處理器的時(shí)間。如果持有鎖的線程很快就釋放了鎖,那么自旋的效率就非常好,反之,自旋的線程就會(huì)白白消耗掉處理的資源,它不會(huì)做任何有意義的工作,這樣反而會(huì)帶來(lái)性能上的浪費(fèi)。所以說(shuō),自旋等待的時(shí)間(自旋的次數(shù))必須要有一個(gè)限度,如果自旋超過(guò)了定義的時(shí)間仍然沒(méi)有獲取到鎖,則應(yīng)該被掛起。

自旋鎖在JDK 1.4.2中引入,默認(rèn)關(guān)閉,但是可以使用-XX:+UseSpinning開開啟,在JDK1.6中默認(rèn)開啟。同時(shí)自旋的默認(rèn)次數(shù)為10次,可以通過(guò)參數(shù)-XX:PreBlockSpin來(lái)調(diào)整。

2.2 自適應(yīng)自旋鎖

JDK 1.6引入了更加智能的自旋鎖,即自適應(yīng)自旋鎖。自適應(yīng)就意味著自旋的次數(shù)不再是固定的,它是由前一次在同一個(gè)鎖上的自旋時(shí)間及鎖的擁有者的狀態(tài)來(lái)決定。那它如何進(jìn)行適應(yīng)性自旋呢?

線程如果自旋成功了,那么下次自旋的次數(shù)會(huì)更加多,因?yàn)樘摂M機(jī)認(rèn)為既然上次成功了,那么此次自旋也很有可能會(huì)再次成功,那么它就會(huì)允許自旋等待持續(xù)的次數(shù)更多。反之,如果對(duì)于某個(gè)鎖,很少有自旋能夠成功,那么在以后要或者這個(gè)鎖的時(shí)候自旋的次數(shù)會(huì)減少甚至省略掉自旋過(guò)程,以免浪費(fèi)CPU資源。

有了自適應(yīng)自旋鎖,隨著程序運(yùn)行和性能監(jiān)控信息的不斷完善,虛擬機(jī)對(duì)程序鎖的狀況預(yù)測(cè)會(huì)越來(lái)越準(zhǔn)確,虛擬機(jī)會(huì)變得越來(lái)越聰明。

2.3 鎖消除

JVM在JIT編譯時(shí)通過(guò)對(duì)運(yùn)行上下文的掃描,經(jīng)過(guò)逃逸分析,對(duì)于某段代碼不存在競(jìng)爭(zhēng)或共享的可能性,就會(huì)講這段代碼的鎖消除,提升程序運(yùn)行效率。

public void method(){
final Object LOCK = new Object();
synchronized (LOCK) {
// do something
}
}

比如上面代碼中鎖,是方法中私有的,又是不可變的,完全沒(méi)必要加鎖,所以JVM就會(huì)執(zhí)行鎖消除。

2.4 鎖粗化

按理來(lái)說(shuō),同步塊的作用范圍應(yīng)該盡可能小,僅在共享數(shù)據(jù)的實(shí)際作用域中才進(jìn)行同步,這樣做的目的是為了使需要同步的操作數(shù)量盡可能縮小,縮短阻塞時(shí)間,如果存在鎖競(jìng)爭(zhēng),那么等待鎖的線程也能盡快拿到鎖。
但是加鎖解鎖也需要消耗資源,如果存在一系列的連續(xù)加鎖解鎖操作,可能會(huì)導(dǎo)致不必要的性能損耗。

鎖粗化就是將多個(gè)連續(xù)的加鎖、解鎖操作連接在一起,擴(kuò)展成一個(gè)范圍更大的鎖,避免頻繁地加鎖解鎖操作。

public void method(Object LOCK){
synchronized (LOCK) {
// do something1
}
synchronized (LOCK) {
// do something2
}
}

比如上面方法中兩個(gè)加鎖的代碼塊,完全可以合并成一個(gè),減少頻繁加鎖解鎖帶來(lái)的開銷,提升程序運(yùn)行效率。

2.5 偏向鎖

為什么要引入偏向鎖?

因?yàn)榻?jīng)過(guò)HotSpot的作者大量的研究發(fā)現(xiàn),大多數(shù)時(shí)候是不存在鎖競(jìng)爭(zhēng)的,通常是一個(gè)線程多次獲得同一把鎖,因此如果每次都要競(jìng)爭(zhēng)鎖會(huì)增大很多沒(méi)有必要付出的代價(jià),為了降低獲取鎖的代價(jià),才引入的偏向鎖。

2.6 輕量級(jí)鎖

輕量級(jí)鎖考慮的是競(jìng)爭(zhēng)鎖對(duì)象的線程不多,而且線程持有鎖的時(shí)間也不長(zhǎng)的場(chǎng)景。因?yàn)樽枞€程需要CPU從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài),代價(jià)較大,如果剛剛阻塞不久這個(gè)鎖就被釋放了,那這個(gè)代價(jià)就有點(diǎn)得不償失了,因此這個(gè)時(shí)候就干脆不阻塞這個(gè)線程,讓它自旋(CAS)這等待鎖釋放。

加鎖過(guò)程:當(dāng)代碼進(jìn)入同步塊時(shí),如果同步對(duì)象為無(wú)鎖狀態(tài)時(shí),當(dāng)前線程會(huì)在棧幀中創(chuàng)建一個(gè)鎖記錄(Lock Record)區(qū)域,同時(shí)將鎖對(duì)象的對(duì)象頭中 Mark Word 拷貝到鎖記錄中,再嘗試使用 CAS 將 Mark Word 更新為指向鎖記錄的指針。如果更新成功,當(dāng)前線程就獲得了鎖。

解鎖過(guò)程:輕量鎖的解鎖過(guò)程也是利用 CAS 來(lái)實(shí)現(xiàn)的,會(huì)嘗試鎖記錄替換回鎖對(duì)象的 Mark Word 。如果替換成功則說(shuō)明整個(gè)同步操作完成,失敗則說(shuō)明有其他線程嘗試獲取鎖,這時(shí)就會(huì)喚醒被掛起的線程(此時(shí)已經(jīng)膨脹為重量鎖)

2.7 重量級(jí)鎖

synchronized是通過(guò)對(duì)象內(nèi)部的監(jiān)視器鎖(Monitor)來(lái)實(shí)現(xiàn)的。但是監(jiān)視器鎖本質(zhì)又是依賴于底層的操作系統(tǒng)的互斥鎖(Mutex Lock)來(lái)實(shí)現(xiàn)的。

重量級(jí)鎖的工作流程:當(dāng)系統(tǒng)檢查到鎖是重量級(jí)鎖之后,會(huì)把等待想要獲得鎖的線程進(jìn)行阻塞,被阻塞的線程不會(huì)消耗cpu。但是阻塞或者喚醒一個(gè)線程時(shí),都需要操作系統(tǒng)來(lái)幫忙,這就需要從用戶態(tài)轉(zhuǎn)換到內(nèi)核態(tài),而轉(zhuǎn)換狀態(tài)是需要消耗很多時(shí)間的,有可能比用戶執(zhí)行代碼的時(shí)間還要長(zhǎng),所以重量級(jí)鎖的開銷還是很大的。

在鎖競(jìng)爭(zhēng)激烈、鎖持有時(shí)間長(zhǎng)的場(chǎng)景,還是適合使用重量級(jí)鎖的。

2.8 鎖升級(jí)過(guò)程

2.9 鎖的優(yōu)缺點(diǎn)對(duì)比

鎖的性能從低到高,依次是無(wú)鎖、偏向鎖、輕量級(jí)鎖、重量級(jí)鎖。不同的鎖只是適合不同的場(chǎng)景,大家可以依據(jù)實(shí)際場(chǎng)景自行選擇。

3. 總結(jié)

synchronized鎖經(jīng)過(guò)多次迭代優(yōu)化,已經(jīng)不像以前那么重了,在JDK1.8的ConcurrentHashMap源碼中已經(jīng)大量使用synchronized做同步控制,大家在日常開發(fā)中可以放心使用了。


新聞標(biāo)題:再有人說(shuō)synchronized是重量級(jí)鎖,就把這篇文章扔給他看
網(wǎng)站地址:http://m.5511xx.com/article/ccdpjod.html