#volatile關鍵字 ##什麼是可見性? 可見性是指線程A改變變數的值後,線程B可以馬上看到更改後變數的值 ##volatile的作用 關鍵字volatile提示線程每次從共用記憶體中讀取數據,而不是從私有記憶體中讀取,這樣就保證了同步數據的可見性 ##關鍵字volatile適用的場景 當想實現一個 ...
volatile關鍵字
什麼是可見性?
可見性是指線程A改變變數的值後,線程B可以馬上看到更改後變數的值
volatile的作用
關鍵字volatile提示線程每次從共用記憶體中讀取數據,而不是從私有記憶體中讀取,這樣就保證了同步數據的可見性
關鍵字volatile適用的場景
當想實現一個線程對一個變數進行修改,希望其他線程可以取到最新的值的時候。就需要對變數使用volatile關鍵字了
我們舉一個例子:
import static java.lang.Thread.sleep;
public class VolatileTest {
public static boolean flag = true;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("線程1 開始!");
while(flag){
}
System.out.println("線程1 結束!");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("線程2 開始!");
flag = false;
System.out.println("flag = " + flag);
}
});
t1.start();
sleep(2000);
t2.start();
}
}
- 運行結果
我們可以看到:程式在一直運行,進入了死迴圈,那麼是什麼原因造成出現了死迴圈呢?
- 我麽在啟動線程t1之後,變數“public static boolean flag = true;”存在於公共堆棧及線程私有的堆棧中,
t1運行後一直線上程私有堆棧中取得的flag的值是true,而線程2的代碼“flag = false;”,修改的是公共堆棧中的
flag,所以t1線程私有堆棧中的flag仍然是true。
解決方法 -添加volatile關鍵字
修改“public static volatile boolean flag = true;”,我們再次運行程式
volatile是否具有原子性?
關鍵字volatile最大的缺點是不支持原子性,如果修改實例中的數據,比如i++,這樣的操作不是原子操作,分為三步
- 從記憶體中取i的值
- 計算i的值
- 將i的值存入記憶體中
如果在第二步計算i的值時,其他線程讀取i的值,並對i進行修改,這個時候就會出現臟數據,解決方法是使用synchronized關鍵字
- 參考資料《Java多線程編程核心技術 第二版》