今天閑來無事跟同事小麥大叔閑聊,
SoWhat:麥叔聽說你偷偷面阿里啦,面的咋樣?
小麥大叔: 一面挺簡單的,主要問了一些基本的數據結構跟算法,還問了下 HashMap的十大常見基本問題。我都答案上來了,還問了我JDK7環,幸虧你那個HashMap環繪制的牛逼,我答的不錯就讓我準備二面了。
SoWhat:二面類?
小麥大叔:二面問了我一些JVM的問題,問我對于JVM內存模型的理解,還有GC的常見理解,最終還問了我下類加載機制,我看你之前水過這個 JVM系列,就依葫蘆畫瓢答上來了,讓我準備三面。
SoWhat:麥叔這波可以啊,三面問的啥啊?
小麥大叔:三面問了我一些CAS、Lock、AQS跟 ConcurrentHashMap 的底層實現什么的,還問了我下線程池的七大參數跟四大拒絕策略,以及使用注意事項。我看你水過 并發編程系列,也就答上來了。
Sowhat:厲害啊這是要過的節奏阿!
小麥大叔:過個錘子,三面的這個總監最后竟然問了我下我對volatile
的底層原理。你妹的你么水,我就答了一些基本的可見性跟弱原子性,然后我感覺面試官不太滿意啊!
Sowhat:額好吧,那我抓緊再水文寫下個關于volatile
的使用。
volatile
變量自身具有下列特性相信大家都知道:
可見性。對一個volatile變量的讀,總是能看到(任意線程)對這個volatile變量最后的寫入。
原子性:對任意單個volatile變量的讀/寫具有原子性,但類似于volatile++這種復合操作不具有原子性。
其中第二點可以理解為把對 volatile 變量的單個讀/寫,看成是使用同一個鎖對這些單個讀/寫操作做了同步,就跟下面的SoWhat
跟SynSoWhat
功能類似哦。
classSoWhat{volatileinti=0;//volatile修飾的變量publicintgetI(){returni;//單個volatile變量的讀}publicvoidsetI(intj){this.i=j;//單個volatile變量的寫}publicvoidinc(){i++;//復合多個volatile變量}}classSynSoWhat{inti=0;publicsynchronizedintgetI(){returni;}publicsynchronizedvoidsetI(intj){this.i=j;}publicvoidinc(){//普通方法調用inttmp=getI();//調用已同步方法tmp=tmp+1;//普通寫方法setI(tmp);//調用已同步方法}}
volatile寫的內存語義如下:
當寫一個
volatile
變量時,JMM會把該線程對應的本地中的共享變量值刷新
到主內存。
publicclassVolasemanteme{inta=0;volatilebooleanflag=false;//這是重點哦publicvoidinit(){a=1;flag=true;//.......}publicvoiduse(){if(flag){inti=a*a;}//.......}}
線程A調用init
方法,線程B調用use
方法。
volatile
讀的內存語義如下:
當讀一個volatile變量時,JMM會把該線程對應的本地內存置為
無效
。線程接下來將從主內存中讀取共享變量。
publicclassVolaSemanteme{inta=0;volatilebooleanflag=false;//這是重點哦publicvoidinit(){a=1;flag=true;//.......}publicvoiduse(){if(flag){inti=a*a;}//.......}}
流程圖大致是這樣的:
volatile
變量的內存可見性是基于內存屏障(Memory Barrier)實現。關于內存屏障的具體講解以前寫過不再重復,JMM裝逼于無形這里說過??偨Y來說就是JMM內部會有指令重排,并且會有af-if-serial
跟happen-before
的理念來保證指令重拍的正確性。內存屏障就是基于4個匯編級別的關鍵字來禁止指令重排的,其中volatile的重拍規則如下:
第一個為讀操作時,第二個任何操作不可重排序到第一個前面。
第二個為寫操作時,第一個任何操作不可重排序到第二個后面。
第一個為寫操作時,第二個的讀寫操作也不運行重排序。
JMM對volatile的內存屏障插入策略
在每個volatile寫操作的前面插入一個StoreStore屏障。在每個volatile寫操作的后面插入一個StoreLoad屏障。
JMM對volatile的內存屏障插入策略
在每個volatile讀操作的后面插入一個LoadLoad屏障。在每個volatile讀操作的后面插入一個LoadStore屏障。
其中重點說下volatile
讀后面為什么跟了個LoadLoad
。加入我有如下代碼 AB兩個線程執行,B線程的flag獲取下面的讀被提前了。
有volatile變量修飾的共享變量進行寫操作的時候會使用CPU
提供的Lock
前綴指令。在CPU級別的功能如下:
將當前處理器緩存行的數據寫回到系統內存
這個寫回內存的操作會告知在其他CPU你們拿到的變量是無效的下一次使用時候要重新共享內存拿。
我們可以通過jitwatch對簡單的代碼進行詳細的反匯編看一下。
packagecom.sowhat.demo;publicclassVolaSemanteme{intunvloatileVal=0;volatilebooleanflag=false;publicvoidinit(){unvloatileVal=1;flag=true;//第九行哦}publicvoiduse(){if(flag){intLocalA=unvloatileVal;if(LocalA==0){thrownewRuntimeException("error");}}}publicstaticvoidmain(String[]args){VolaSemantemevolaSemanteme=newVolaSemanteme();volaSemanteme.init();volaSemanteme.use();}}
對普通變量的賦值操作:
對volatile
變量的賦值操作。
可以對比得出,volatile 修飾的變量確實會多一個 lock addl $0x0,(%rsp) 指令。
0x0000000114ce95cb:lockaddl$0x0,(%rsp);*putfieldflag;-com.sowhat.demo.VolaSemanteme::init@7(line9)
到此,相信大家對“volatile是什么”有了更深的了解,不妨來實際操作一番吧!這里是本站網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
c語言中正確的字符常量是用一對單引號將一個字符括起表示合法的字符常量。例如‘a’。數值包括整型、浮點型。整型可用十進制,八進制,十六進制。八進制前面要加0,后面...
2022年天津專場考試原定于3月19日舉行,受疫情影響確定延期,但目前延期后的考試時間推遲。 符合報名條件的考生,須在規定時間登錄招考資訊網(www.zha...
:喜歡聽,樂意看。指很受歡迎?!巴卣官Y料”喜聞樂見:[ xǐ wén lè jiàn ]詳細解釋1. 【解釋】:喜歡聽,樂意看。指很受歡迎。2. 【示例】:這是...
存貸比是什么意思?銀行存貸比是指銀行貸款總額/存款總額,存貸比越高,說明銀行資金得到了充足的運用,可以為銀行帶來更多的效益,但同時也會帶來較高的風險。銀行在經營過程中,不僅要達成一定的效益,也要應對客戶的取款需求,因此存貸比不宜過高也不宜過低。銀行存貸比多少合適?依據國家相關規定,商業銀行存貸比不得超過75%。對資本充足率、撥備覆蓋率良好的中小銀行,允許有條件適當突破存貸比。存貸比和貸存比一樣嗎?...
商業地產運營模式是什么樣的?一般來說,商業地產是指用于零售,餐飲、娛樂、健身服務和休閑等各種商業目的的房地產形式。具有房地產、商業、投資的特點,不同于單純的投資和商業,也不同于傳統的房地產行業;大致可分為商業廣場、購物廣場、商業街,大型商店、購物中心、休閑廣場、步行街, 專業市市場、社區商業中心等。它在商業模式、功能和用途上都不同于普通的住宅、公寓、別墅等房地產形式。以辦公為主要目的的房地產屬于商...
在辦公室坐八個小時,不知不覺總會出現各種小問題。腰有點酸,肩膀總有小疼,還有皮膚干燥,月經不調,等等。這些小問題是否讓你只是單純的“累”來說明問題?疲勞、壓力、坐姿甚至辦公室里的空音調都可能不斷侵犯你的健康和美麗,調整這些不良狀況并不難。學習中醫艾灸,每天只需10分鐘,就能讓你輕松告別小毛??!迎來一個精神清爽、膚色如春的全新好狀態。古老而神秘的艾灸,如今已經成為養生專家和美容專家之間的新時尚。艾灸...