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變量值就相當于進入同步塊(會先清空本地內存變量值,從主內存獲取最新值)。
轉自http://ifeve.com/%E9%AB%98%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E5%BF%85%E5%A4%87%E5%9F%BA%E7%A1%80/
/**
* 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的注釋,看看結果.