final添加内存屏障问题
看了 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大佬过来讨论讨论到底怎么回事?