java 高并發(fā)中volatile的實(shí)現(xiàn)原理
java 高并發(fā)中volatile的實(shí)現(xiàn)原理
摘要: 在多線(xiàn)程并發(fā)編程中synchronized和Volatile都扮演著重要的角色,Volatile是輕量級(jí)的synchronized,它在多處理器開(kāi)發(fā)中保證了共享變量的“可見(jiàn)性”??梢?jiàn)性的意思是當(dāng)一個(gè)線(xiàn)程修改一個(gè)共享變量時(shí),另外一個(gè)線(xiàn)程能讀到這個(gè)修改的值。它在某些情況下比synchronized的開(kāi)銷(xiāo)更小
1. 定義:
java編程語(yǔ)言允許線(xiàn)程訪(fǎng)問(wèn)共享變量,為了確保共享變量能被準(zhǔn)確和一致的更新,線(xiàn)程應(yīng)該確保通過(guò)排他鎖單獨(dú)獲得這個(gè)變量。Java語(yǔ)言提供了volatile,在某些情況下比鎖更加方便。如果一個(gè)字段被聲明成volatile,java線(xiàn)程內(nèi)存模型確保所有線(xiàn)程看到這個(gè)變量的值是一致的
2. volatile實(shí)現(xiàn)原理
那么Volatile是如何來(lái)保證可見(jiàn)性的呢?在x86處理器下通過(guò)工具獲取JIT編譯器生成的匯編指令來(lái)看看對(duì)Volatile進(jìn)行寫(xiě)操作CPU會(huì)做什么事情。
Java代碼: instance = new Singleton();//instance是volatile變量
匯編代碼: 0x01a3de1d: movb $0x0,0x1104800(%esi);0x01a3de24: lock addl $0x0,(%esp);
有volatile變量修飾的共享變量進(jìn)行寫(xiě)操作的時(shí)候會(huì)多第二行匯編代碼,通過(guò)查IA-32架構(gòu)軟件開(kāi)發(fā)者手冊(cè)可知,lock前綴的指令在多核處理器下會(huì)引發(fā)了兩件事情。
將當(dāng)前處理器緩存行的數(shù)據(jù)會(huì)寫(xiě)回到系統(tǒng)內(nèi)存。
這個(gè)寫(xiě)回內(nèi)存的操作會(huì)引起在其他CPU里緩存了該內(nèi)存地址的數(shù)據(jù)無(wú)效。
處理器為了提高處理速度,不直接和內(nèi)存進(jìn)行通訊,而是先將系統(tǒng)內(nèi)存的數(shù)據(jù)讀到內(nèi)部緩存(L1,L2或其他)后再進(jìn)行操作,但操作完之后不知道何時(shí)會(huì)寫(xiě)到內(nèi)存,如果對(duì)聲明了Volatile變量進(jìn)行寫(xiě)操作,JVM就會(huì)向處理器發(fā)送一條Lock前綴的指令,將這個(gè)變量所在緩存行的數(shù)據(jù)寫(xiě)回到系統(tǒng)內(nèi)存。但是就算寫(xiě)回到內(nèi)存,如果其他處理器緩存的值還是舊的,再執(zhí)行計(jì)算操作就會(huì)有問(wèn)題,所以在多處理器下,為了保證各個(gè)處理器的緩存是一致的,就會(huì)實(shí)現(xiàn)緩存一致性協(xié)議,每個(gè)處理器通過(guò)嗅探在總線(xiàn)上傳播的數(shù)據(jù)來(lái)檢查自己緩存的值是不是過(guò)期了,當(dāng)處理器發(fā)現(xiàn)自己緩存行對(duì)應(yīng)的內(nèi)存地址被修改,就會(huì)將當(dāng)前處理器的緩存行設(shè)置成無(wú)效狀態(tài),當(dāng)處理器要對(duì)這個(gè)數(shù)據(jù)進(jìn)行修改操作的時(shí)候,會(huì)強(qiáng)制重新從系統(tǒng)內(nèi)存里把數(shù)據(jù)讀到處理器緩存里。
Lock前綴指令會(huì)引起處理器緩存回寫(xiě)到內(nèi)存。Lock前綴指令導(dǎo)致在執(zhí)行指令期間,聲言處理器的 LOCK# 信號(hào)。在多處理器環(huán)境中,LOCK# 信號(hào)確保在聲言該信號(hào)期間,處理器可以獨(dú)占使用任何共享內(nèi)存。(因?yàn)樗鼤?huì)鎖住總線(xiàn),導(dǎo)致其他CPU不能訪(fǎng)問(wèn)總線(xiàn),不能訪(fǎng)問(wèn)總線(xiàn)就意味著不能訪(fǎng)問(wèn)系統(tǒng)內(nèi)存),但是在最近的處理器里,LOCK#信號(hào)一般不鎖總線(xiàn),而是鎖緩存,畢竟鎖總線(xiàn)開(kāi)銷(xiāo)比較大。在8.1.4章節(jié)有詳細(xì)說(shuō)明鎖定操作對(duì)處理器緩存的影響,對(duì)于Intel486和Pentium處理器,在鎖操作時(shí),總是在總線(xiàn)上聲言L(fǎng)OCK#信號(hào)。但在P6和最近的處理器中,如果訪(fǎng)問(wèn)的內(nèi)存區(qū)域已經(jīng)緩存在處理器內(nèi)部,則不會(huì)聲言L(fǎng)OCK#信號(hào)。相反地,它會(huì)鎖定這塊內(nèi)存區(qū)域的緩存并回寫(xiě)到內(nèi)存,并使用緩存一致性機(jī)制來(lái)確保修改的原子性,此操作被稱(chēng)為“緩存鎖定”,緩存一致性機(jī)制會(huì)阻止同時(shí)修改被兩個(gè)以上處理器緩存的內(nèi)存區(qū)域數(shù)據(jù)。
一個(gè)處理器的緩存回寫(xiě)到內(nèi)存會(huì)導(dǎo)致其他處理器的緩存無(wú)效。IA-32處理器和Intel 64處理器使用MESI(修改,獨(dú)占,共享,無(wú)效)控制協(xié)議去維護(hù)內(nèi)部緩存和其他處理器緩存的一致性。在多核處理器系統(tǒng)中進(jìn)行操作的時(shí)候,IA-32 和Intel 64處理器能嗅探其他處理器訪(fǎng)問(wèn)系統(tǒng)內(nèi)存和它們的內(nèi)部緩存。它們使用嗅探技術(shù)保證它的內(nèi)部緩存,系統(tǒng)內(nèi)存和其他處理器的緩存的數(shù)據(jù)在總線(xiàn)上保持一致。例如在Pentium和P6 family處理器中,如果通過(guò)嗅探一個(gè)處理器來(lái)檢測(cè)其他處理器打算寫(xiě)內(nèi)存地址,而這個(gè)地址當(dāng)前處理共享狀態(tài),那么正在嗅探的處理器將無(wú)效它的緩存行,在下次訪(fǎng)問(wèn)相同內(nèi)存地址時(shí),強(qiáng)制執(zhí)行緩存行填充
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
idea如何關(guān)閉右側(cè)類(lèi)顯示方法
這篇文章主要介紹了idea如何關(guān)閉右側(cè)類(lèi)顯示方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Java中常見(jiàn)字符串拼接九種方式詳細(xì)例子
這篇文章主要給大家介紹了關(guān)于Java中常見(jiàn)字符串拼接的九種方式,字符串拼接是我們?cè)贘ava代碼中比較經(jīng)常要做的事情,就是把多個(gè)字符串拼接到一起,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07
myeclipse創(chuàng)建servlet_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了myeclipse創(chuàng)建servlet的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Spring創(chuàng)建bean對(duì)象三種方式代碼實(shí)例
這篇文章主要介紹了Spring創(chuàng)建bean對(duì)象三種方式代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
SpringData JPA Mongodb查詢(xún)部分字段問(wèn)題
這篇文章主要介紹了SpringData JPA Mongodb查詢(xún)部分字段問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
zookeeper+Springboot實(shí)現(xiàn)服務(wù)器動(dòng)態(tài)上下線(xiàn)監(jiān)聽(tīng)教程詳解
這篇文章主要介紹了zookeeper+Springboot實(shí)現(xiàn)服務(wù)器動(dòng)態(tài)上下線(xiàn)監(jiān)聽(tīng),主要介紹了什么是服務(wù)器動(dòng)態(tài)上下線(xiàn)監(jiān)聽(tīng)及為什么要實(shí)現(xiàn)對(duì)服務(wù)器上下線(xiàn)的監(jiān)聽(tīng),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
SpringBoot集成極光推送的實(shí)現(xiàn)代碼
工作中經(jīng)常會(huì)遇到服務(wù)器向App推送消息的需求,一般企業(yè)中選擇用極光推送的比較多,本文就介紹了SpringBoot集成極光推送的實(shí)現(xiàn)代碼,感興趣的可以了解一下2023-08-08
詳解SpringCloud Ribbon 負(fù)載均衡通過(guò)服務(wù)器名無(wú)法連接的神坑
這篇文章主要介紹了詳解SpringCloud Ribbon 負(fù)載均衡通過(guò)服務(wù)器名無(wú)法連接的神坑,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-06-06

