看了 why大佬的 博客一個困擾我122天的技術問題,我好像知道答案了。
發現他留了個坑,在變量i類型為 int 或者 Integer 時,int類型的i死循環了而Integer類型的i可以結束
int
類型的i,出現死循環的機會是隨機的,可能需要多來幾次,估計1000來次吧
代碼在下面,各位大佬可以拿去測測
public class VolatileDemo {
private static boolean flag = false;
private static int i = 0;
// (3)
// private static Integer i = 0;
// (4)
// private volatile static int i = 0;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
// try {
// TimeUnit.MILLISECONDS.sleep(100);
flag = true;
// System.out.println("flag 被修改成 true");
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}).start();
while (!flag) {
i++;
// (1)
// System.out.println("flag標識 = " + flag);
// (2)
// try {
// TimeUnit.MILLISECONDS.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
System.out.println("程序結束,i=" + i);
}
}
當時考慮的問題是 int
類型在棧上而 Integer
類型出現在堆上,一個普通類型另一個引用類型,在群里一陣討論
最后在一個群友提示下發現了問題的關鍵,Integer
底層的 value
用了 final
修飾
final
修飾變量,看過《java並發編程藝術》應該知道,它專門對final
做了一個大章節的說明
最最重要的是它會添加內存屏障storestore
,問題看起來是解決了
但新的問題出現了,還是看過《java並發編程藝術》的都知道,x86對寫寫,讀寫,讀讀內存屏障默認忽略,只對storeload
有效
書本上又說道既然它加了storestore
,x86無視它,那么為啥final
會生效呢???
此處@why大佬過來討論討論到底怎么回事?