天天看點

java voliate_voliate關鍵字及其示例

大家好,又見面了,我是你們的朋友全棧君。

voliate關鍵字

1 使變量線上程間可見

對于避免不可見性問題,Java還提供了一種弱形式的同步,即使用了volatile關鍵字。該關鍵字確定了對一個變量的更新對其他線程可見。當一個變量被聲明為volatile時候,線程寫入時候不會把值緩存在寄存器或者或者在其他地方,當線程讀取的時候會從主記憶體重新擷取最新值,而不是使用目前線程的拷貝記憶體變量值。volatile雖然提供了可見性保證,但是不能使用他來建構複合的原子性操作,也就是說當一個變量依賴其他變量或者更新變量值時候新值依賴目前老值時候不在适用。與synchronized相似之處在于

如圖線程A修改了volatile變量b的值,然後線程B讀取了改變量值,那麼所有A線程在寫入變量b值前可見的變量值,在B讀取volatile變量b後對線程B都是可見的,圖中線程B對A操作的變量a,b的值都可見的。volatile的記憶體語義和synchronized有類似之處,具體說是說當線程寫入了volatile變量值就等價于線程退出synchronized同步塊(會把寫入到本地記憶體的變量值同步到主記憶體),讀取volatile變量值就相當于進入同步塊(會先清空本地記憶體變量值,從主記憶體擷取最新值)。

/**

* Created by lixiaodong on 2017/6/23.

*/

public class Test extends Thread{

//voliate

private String i =”sss”;

private void setI(String i){

this.i=i;

}

@Override

public void run() {

System.out.println(“進入方法”+i);

while (i.equals(“sss”)){

// System.out.println(“方法執行”);

//

// try {

// Thread.sleep(3000);

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

}

System.out.println(“線程結束”);

}

public static void main(String[] args ) throws InterruptedException{

Test test=new Test();

test.start();

Thread.sleep(1000);

System.out.println(“線程設定了stop”);

test.setI(“線程設定了stop”);

}

}

上面是一個簡單的示例。

首先運作代碼,可以看到,盡管将變量設定了stop,test線程并沒有如預期的停止.說明,test線程内的i的并沒有被修改,test隻是在start時将i變量拷貝到了線程自有的一塊空間内,與主線内的i變量互不影響.

将voliate關鍵字放在變量i的聲明上,運作發現程式正常停止.可見變量i在任何一個線程内都是可見的,當變量i在主線程被修改時,子線程立即獲得了被更新的值.

最坑的地方來了,打開代碼中的while循環中的列印語句,将voliate關鍵字注釋掉,執行代碼.神奇的事情發生了,程式正常的停止了,WTF!(在我最開始研究voliate的時候,我一直有這句輸出語句,一直得不到正确結果)這是為啥呢?下面這段話基本說明了問題,同時你也可以将輸出語句注釋點,打開sleep的注釋,看看結果.

JVM會盡力保證記憶體的可見性,即便這個變量沒有加同步關鍵字。換句話說,隻要CPU有時間,JVM會盡力去保證變量值的更新。這種與volatile關鍵字的不同在于,volatile關鍵字會強制的保證線程的可見性。而不加這個關鍵字,JVM也會盡力去保證可見性,但是如果CPU一直有其他的事情在處理,它也沒辦法。最開始的代碼,一直處于試了循環中,CPU處于一直被飽受占用的時候,這個時候CPU沒有時間,JVM也不能強制要求CPU分點時間去取最新的變量值。而加了System.out.println之後,由于内部代碼的同步關鍵字的存在,導緻CPU的輸出其實是比較耗時的。這個時候CPU就有可能有時間去保證記憶體的可見性,于是while循環可以被終止。其實,也可以在while循環裡面加上sleep,讓run方法放棄cpu,但是不放棄鎖,這個時候由于CPU有空閑的時候就去按照JVM的要求去保證記憶體的可見性。如下圖所示。 run方法裡面休息了3秒,cpu有充足的空閑時間去取變量的最新值,是以循環執行一次就停止了。(轉自http://blog.csdn.net/weililansehudiefei/article/details/70904111)

釋出者:全棧程式員棧長,轉載請注明出處:https://javaforall.cn/131410.html原文連結:https://javaforall.cn