前面的博文說了java的內存模型,介紹了java內存模型的基礎,此篇文章來講一下volatile關鍵字,這個在併發編程中,佔有舉足輕重地位的關鍵字。java
在java5.0 以前它是一個備受爭議的關鍵字,5以後它重獲新生。volatile關鍵字的做用是保證多線程中變量的可見性,是JUC包中的核心。編程
在內存模型基礎中,已經提到過,JVM是分爲堆內存和棧內存的,堆內存在線程之間共享,而棧內存爲線程內部私有,對其餘線程不可見。爲保證變量的可見性,可使用volatile修飾,那爲何使用了關鍵字volatile修飾後,就能保證可見性,下面進行分析。緩存
volatile 能夠看做是一個輕量級的鎖,這麼說多是不許確的,但它確實具有了鎖的一些特性。與鎖的區別是,鎖保證原子性,鎖住的多是是個變量或者一段代碼,而volatile修飾的變量只能保證變量在線程之間的傳遞,只能保證可見性,在一些方面並無具有原子性。多線程
因此上面的話有兩層語義:併發
volatile變量的讀/寫,能夠實現線程之間的通訊。ide
初始時,兩個線程的本地內存中的flag和a都是初始狀態,線程A在寫flag變量後,本地內存A中更新過的兩個共享變量的值被刷新到主內存中,在讀flag變量後,本地內存中包含的值已經被置爲無效,此時線程B必須從主內存中讀取共享變量。性能
爲了實現volatile的內存語義,編譯器在生成字節碼時,會在指令序列中插入內存屏障,來禁止特定類型的處理器重排序。JMM採用了保守策略,規則以下:spa
記得曾經看過一篇文章,講述的是volatile關鍵字修飾的變量,編程彙編代碼後,會在變量的前面插入一條LOCK指令。.net
Java代碼: instance = new Singleton();//instance是volatile變量 彙編代碼: 0x01a3de1d: movb $0x0,0x1104800(%esi);0x01a3de24: lock addl $0x0,(%esp);
經過上面的代碼發現,volatile修飾的變量會多出一個lock指令,LOCK指令屬於系統層級: LOCK前綴會使處理器執行當前指令時產生一個LOCK#信號,顯示的鎖定總線。線程
先啓動一個線程thread,因爲isOver=fasle,因此thread裏的run方法裏的while是一個死循環,而後企圖在main線程裏改變標誌位isOver=true,從而想終止thread裏的while死循環,使得thread線程可以結束退出。但是,事與願違,實驗現象是沒有中止,即thread裏isOver依然爲false仍是處於死循環。
public class VolatileDemo { private static boolean isOver = false; public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { while (!isOver) ; } }); thread.start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } isOver = true; } }
更正後的代碼爲:
public class VolatileDemo { private static volatile boolean isOver = false; public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { while (!isOver) ; } }); thread.start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } isOver = true; } }
注意不一樣點,如今已經將isOver設置成了volatile變量,這樣在main線程中將isOver改成了true後,thread的工做內存該變量值就會失效,從而須要再次從主內存中讀取該值,如今可以讀出isOver最新值爲true從而可以結束在thread裏的死循環,從而可以順利中止掉thread線程。如今問題也解決了,知識也學到了:)。
volatile是一種比鎖更輕量級的線程之間通訊的機制,volatile僅僅保證對單個volatile變量的讀/寫具備原子性,而鎖的互斥執行的特性能夠保證對整個臨界區代碼執行具備原子性,在功能上,鎖比voatile更強大,在可伸縮性和執行性能上,volatile更有優點,可是volatile並不能代替鎖。
參考:
java併發編程藝術