由指令重排序引起的可见性问题: public class Test { // 如果运行时加上 -server 下面的代码就变成了死循环,没有加就正常运行。(运行器的编译优化只有在服务器模式下才执行) // 通过设置JVM参数,打印出JIT(即时编译)编译的内容(这里说的编译不是指class文件的编译,而是指未变级别的编译) private boolean flag = true; // -server -Djava.compiler=NONE 参数可以关闭jit优化。 // 在多线程中,由于指令重排序引起的线程可见性问题。 public static void main(String[] args) throws IOException, InterruptedException { Test demo1 = new Test(); new Thread(new Runnable() { @Override public void run() { int i = 0; // class文件在运行时jit编译成为汇编指令,汇编指令出现了重排序。 /* // 重排序后的逻辑。因为while语句里面需要一直判断flag。所以jvm优化为外层使用if判断一次。 if(demo1.flag){ while (true){ i++; } } hot code : 热点代码。(就像是下面的while语句中的内容,执行频率很高。jvm认为是热点代码) */ while (demo1.flag) { i++; } System.out.println("i = " + i); } }).start(); TimeUnit.SECONDS.sleep(2); // 设置flag为false,使上面的线程结束循环。 demo1.flag = false; System.out.println("主线程结束"); } } 问题描述: 多个CPU执行多个线程任务时,由于线程栈时独享的,如果共享数据在缓存中跟新不及时,会出现多线程共享数据不一致。(基本不可能出现) 运行时编译器JIT,将class编译称为汇编指令。在服务器模式下。会对执行的顺序进行优化重排序。但是放在多线程中执行时会由于执行的顺序改变执行的结果。 由于指令进行了重排序。导致缓存的修改对本线程不可见。 (指令重排序导致了while语句变成了if执行,之后在多线程的情况下。一个线程先判断if,另外一个线程后修改条件。所以if语句中的内容不会执行了。) (指令重排序是为了:提高CPU的使用率。一个线程阻塞的时候,别的线程继续执行。) 内存模型规范(为了使共享数据及时可见): 可以在线程之间共享的内存称为:共享内存或堆内存。所有实例字段、静态字段和数组元素都存储在堆内存中。 定义了线程的操作:write、read、lock、unlock、启动、终止、同步规则(加锁解锁) 如果一个线程没有数据竞争,那么程序的所有执行看起来都是顺序一致的。 oracle文档官网: docs.oracle.com
来源:https://www.cnblogs.com/Xmingzi/p/12601067.html