1. 程式人生 > >JAVA併發程式設計之Volatile變數

JAVA併發程式設計之Volatile變數

volatile:不穩定的;爆炸性的;反覆無常的

volatile變數是java提供的一種弱同步機制(我覺得只能確保讀取的同步)當把變數宣告為volatile型別後:

            1.編譯器與執行時都會注意到這個變數是共享的,會變的,不會將該變數上的操作與其他記憶體操作一起重排序;

            2.volatile變數不會被快取在暫存器或者處理器不可見的地方;

因此,讀取volatile型別的變數時總會返回最新值。

package JavaConcurrency;

public class TestVolatile {
	private static volatile boolean value=true;
	
	private static class ThreadOne extends Thread{
		public void run(){
				
				if(value){
					System.out.println("value is :"+value);
				}else{
					System.out.println("value is :"+value);
				}
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				
		}
	}
	private static class ThreadTwo extends Thread{
		public void run(){
				if(value){
					value=false;
				}
				
				if(!value){
					value=true;
				}
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
		}
	}
	public static void main(String[] args) throws InterruptedException{
	
		for (int i = 0; i < 100; i++) {
			new ThreadTwo().start();
			new ThreadOne().start();
		}
		Thread.sleep(500);
		System.out.println("============GAME OVER===============");
	}
}

以上程式碼中,ThreadOne 輸出布林型變數value的值,ThreadTwo 改變value的值,使其在false和true之間轉換。

        當不用volatile修飾value時,ThreadOne將value的值true快取在ThreadOne的本地記憶體中,每次都從本次記憶體中取值,而不去理會原地址value的值是否發生了變化,因此輸出value的值全為true;使用volatile修飾變數value後,ThreadOne會從原地址對value進行取值,值為false的value會出現在結果中。這就會出現有時候debug版本下程式能正常而生產環境下卻不正常。

檢查某個狀態標記以判斷dosomething(通常為結束迴圈)是volatile的一種典型用法:

volatile boolean asleep;
    while(!aleep)
        dosomething();

注意:加鎖機制能確保可見性,也能確保原子性,volatile只能確保可見性。

        volatile變數也存在一些侷限性,比如不能確保(value++)操作的原子性,除非我們能確保只有一個執行緒對變數執行寫操作(原子變數實現對變數讀-改-寫的原子操作),當且僅當滿足以下條件時,才應該使用volatile變數:

1.對變數的寫入操作不依賴變數的當前值,或者你能確保單個執行緒更新變數的值;

2.該變數不會與其他狀態變數條件一起納入不變性條件中;

3.在訪問變數時不需要加鎖