07:线程安全-可见性问题

心不动则不痛 提交于 2020-03-30 22:57:40
由指令重排序引起的可见性问题:
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
     
    
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!