Java-volatile底層實現原理


一.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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM