首先來看一個經典的關于變數記憶體可見性的案例:
public class TestVolatile {
public static void main(String[] args) throws InterruptedException {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
if(td.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
}
程式運行結果是

td 執行緒修改了flag的值為true,但是主執行緒中flag的快取還是false,由于while(true)回圈效率極高,主執行緒來不及去主存中讀取新的flag值,從而主執行緒一直在回圈,
改變這種現象的辦法有三種:
1)讓回圈沉睡一秒
while (true) {
if (td.isFlag()) {
System.out.println("------------------");
break;
}
Thread.sleep(100);
}
讓主執行緒沉睡一秒,這樣就有足夠的時間去主存中取值,
2)給回圈加synchronized同步鎖
synchronized (td) {
while (true) {
if (td.isFlag()) {
System.out.println("------------------");
break;
}
Thread.sleep(100);
}
}
3)以上方法效率比較低,第三種方法就是給變數flag加volatile關鍵字
private volatile boolean flag = false;

volatile能保證共享資料的記憶體可見性,這樣主執行緒每次讀取到的flag都是主存中的資料,而不是主執行緒快取中的資料,那么volatile是怎么做到的呢?

這里volatile變數 只是規定read、load、use(ssign、store、write)動作必須連續出現,并沒有規定這三個動作的組合是原子操作,所以volatile只保證記憶體可見性,不保證原子性,不是執行緒安全的,只是保證每次從主存中讀資料,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/235430.html
標籤:其他
