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大佬过来讨论讨论到底怎么回事?

原文地址:https://www.cnblogs.com/bangiao/p/13180028.html