筆記15(volatile)
程式碼:
public class Main {
public static void main(String[] args) throws InterruptedException {
MyThread<Integer> t = new MyThread<Integer>();
System.out.println("========開始執行========");
new Thread(t).start();
System.out.println("執行到這了F1");
t.isEnd();
System.out.println("執行到這了F3");
}
}
class MyThread<V> implements Runnable {
public boolean flag = false;
@Override
public void run() {
int t = 0;
for (int n = 1; n <= 5; n++) {
System.out.println(n);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
t += n;
}
System.out.println("總和:"+t);
System.out.println("更新flag值!!!");
flag = true;
}
public void isEnd() throws InterruptedException {
while (true) {
// System.out.println("執行到這了F2");
if (this.flag) {
System.out.println("=========執行完畢========");
break;
}
}
}
}
上面程式碼執行結果是如下,從程式上來看由於執行緒間的不可見性,執行起來就進入了一個死迴圈。
這裡可以通過volatile使共享變數線上程間保持可見性,解決上面的問題,volatile有同步作用,可以強制將修改後的共享變數推送給所有執行緒,volatile修飾的基本型別變數在讀取時可以保證變數值是最新的(但不保證原子性)。
在while(true)迴圈中加一行程式碼: System.out.println("執行到這了F2");
程式在迴圈n次之後正常結束了。
從以上輸出結果看,子執行緒在執行完for迴圈後修改了flag值,回寫給主記憶體,isEnd方法所線上程也拿到了共享變數修改後的值。
另:或者加上Thread.sleep(100);也可以正常結束。
不同執行緒對共享變數是相互不可見的,通常可以使用volatile和Synchronized來實現可見性
事實上非短時間內高併發的情況下,即使沒有保證可見性的措施,很多時候共享變數依然能夠在主記憶體和工作記憶體間得到及時的更新。
最後還有一個問題,為什麼不加上一段輸出語句執行緒間共享變數就沒辦法重新整理。