一.volatile
代碼
package jvm; public class VolatileVisibilityTest { private static boolean initFlag = false; // private static volatile boolean initFlag = false; public static void main(String[] args) throws InterruptedException { new Thread(new Runnable() { public void run() { System.out.println("waiting data....."); while(!initFlag) { } System.out.println("success....."); } }).start(); Thread.sleep(2000); new Thread(new Runnable() { public void run() { prepareData(); } }).start(); } public static void prepareData() { System.out.println("prapareing data......"); initFlag = true; System.out.println("prapareing data end......"); } }
1.不使用volatile,運行結果:
waiting data..... prapareing data...... prapareing data end......
2.使用volatile,運行結果:
waiting data..... prapareing data...... prapareing data end...... success.....
JMM數據原子操作
-
read(讀取):作用於主內存,它把變量值從主內存傳送到線程的工作內存中,以便隨后的load動作使用;
-
load(載入):作用於工作內存,它把read操作的值放入工作內存中的變量副本中;
-
use(使用):作用於工作內存,它把工作內存中的值傳遞給執行引擎,每當虛擬機遇到一個需要使用這個變量的指令時候,將會執行這個動作;
-
assign(賦值):作用於工作內存,它把從執行引擎獲取的值賦值給工作內存中的變量,每當虛擬機遇到一個給變量賦值的指令時候,執行該操作;
-
store(存儲):作用於工作內存,它把工作內存中的一個變量傳送給主內存中,以備隨后的write操作使用;
-
write(寫入):作用於主內存,它把store傳送值放到主內存中的變量中。
- lock(鎖定):作用於主內存,它把一個變量標記為一條線程獨占狀態;
-
unlock(解鎖):作用於主內存,它將一個處於鎖定狀態的變量釋放出來,釋放后的變量才能夠被其他線程鎖定;
voliate緩存可見性實現原理:
底層實現主要是通過匯編lock前綴指令,它會鎖定這塊區域內的緩存(緩存行鎖定)並會回寫到主內存。
IA-32架構開發者對lock指令的解釋:
1)會將當前處理器緩存行的數據立即寫會系統主存
2)這個寫回內存的操作會引起在其他cpu里緩存了該內存地址的數據無效(MES協議)
線程2將initFlag的值store到主內存時要通過總線,cpu總線嗅探機制監聽到initFlag值被修改,線程1的initFlag失效,線程1需要重新read initFlag的值。
二.synchronize
代碼:
package concurrent; public class VolatileAtumicTest { private static volatile int num = 0; public static void increse() { // public static synchronized void increse() { num++; } public static void main(String[] args) throws InterruptedException { Thread[] threads = new Thread[10]; for(int i=0; i<threads.length; i++) { threads[i] = new Thread(new Runnable() { public void run() { for(int i=0; i<1000; i++) { increse(); } } }); threads[i].start(); } for(Thread t : threads) { t.join(); } System.out.println(num); } }
不加synchronized,輸出:
num<=10000
加上synchronized,輸出:
10000