基礎(chǔ)概念
volatile 是一個Java 中的關(guān)鍵字,一個提供基礎(chǔ)同步屬性的關(guān)鍵字。針對JVM重排序在并發(fā)場景下的問題,被vlolatile修飾的關(guān)鍵詞摘能,編譯器不會將該變量的操作與其他內(nèi)存操作進行重排序。
1敲街、重排序:如果熟悉JVM的話团搞,應(yīng)該就很清楚Java的重排序了。重排序主要分為:編譯器優(yōu)化的重排序聪富、指令級別并行的重排序莺丑、內(nèi)存系統(tǒng)的重排序。其中編譯器重排序:在不改變代碼語義的情況下墩蔓,優(yōu)化性能而改變了代碼執(zhí)行順序梢莽。指令并行的重排序:處理器采用并行技術(shù)使多條指令重疊執(zhí)行,在不存在數(shù)據(jù)依賴的情況下奸披,改變機器指令的執(zhí)行順序昏名。內(nèi)存系統(tǒng)的重排序:使用緩存和讀寫緩沖區(qū)時,加載和存儲可能是亂序執(zhí)行阵面。
2轻局、JMM:java 內(nèi)存模型(一種語言級別的內(nèi)存模型),Java內(nèi)存模型分為一個工作線程样刷、線程私有的工作內(nèi)存仑扑、共享的主存。
3置鼻、as-if-serial:無論怎么排镇饮,要保證和串行執(zhí)行的結(jié)果一致。對于單線程來說箕母,對存在依賴關(guān)系的操作進行重排序储藐,不會改變最后的執(zhí)行結(jié)果俱济,在多線程程序中,對存在依賴關(guān)系的操作進行重排序钙勃,可能會改變最后的執(zhí)行結(jié)果蛛碌。就需要我們自己來保證as-if-serial了。
4辖源、hanpens-before:指前一個操作對后一個操作可見蔚携。(注意一點:不是前一個操作必須在后一個操作之前執(zhí)行,不是串行執(zhí)行)
看完這三個前提克饶,就可以去理解volatile了浮梢,
volatile原理
volatile更像是語言層面,對于JVM執(zhí)行過程中對于重排序的限制彤路,是一種內(nèi)存屏障,這個屏障就像是一堵墻芥映,阻止了前后的重排序操作(具體屏障:LoadLoad屏障和LoadStore屏障)
StoreStore洲尊、StoreLoad
volatile 保證了一種可見性,什么意思呢奈偏,就是說volatile修飾的變量坞嘀,產(chǎn)生變化時,立馬寫入主存惊来。保證其他線程能發(fā)現(xiàn)其變化丽涩,保證了正確性,也就是happens-before裁蚁。
常見問題
1矢渊、volatile不是鎖,僅僅是一種程序執(zhí)行過程中的指令級的同步策略枉证,保證了可見性矮男、避免重排序
2、volatile能夠維持被修飾變量單個的原子操作室谚。所以說毡鉴,對于volatile double 進行單個寫操作在多線程并發(fā)環(huán)境下是完全正常的。這里注意一點秒赤,一定是單個操作猪瞬,像是i++; i--入篮;之類的這明顯是復(fù)合操作哈陈瘦,別較真當作單個操作。
使用場景
1崎弃、保證long甘晤、double等的單個操作的原子性含潘,不至于寫完一半被讀走。
2线婚、作為基礎(chǔ)信號量遏弱,發(fā)生變化時,能夠其他線程周知塞弊,但記住一點復(fù)合操作可不保證原子性漱逸,讀后寫什么的在多線程并發(fā)環(huán)境下還是進行同步操作吧。
volatile 差不多就這些游沿,真正的使用體驗可以嘗試自己寫demo饰抒,比如說通過信號量改變打斷死循環(huán),多線程瘋狂i++操作等诀黍〈樱看concurrent包中的源碼時,volatile是必須要理解的眯勾。