文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

从零开始理解 Java 内存模型——可见性与有序性详解

2024-11-28 14:31

关注

2.编译器重排序

编译器(包括 JVM、JIT 编译器等)重排序即不影响单线程执行结果的情况下,会针对性的重排代码的效率以提高单线程情况下代码执行效率。当然这种重排序可能也会存在一些问题,假设我们现在有这样一段代码,双方先对各自的localNum初始化,然后用变量x、y读取变量localNum的值,假设发生指令重排序就会导致x、y拿到默认的零值而输出0:

对于这种情况,JMM会针对性发生这种重排序的编译器进行禁止来解决这种问题。

3.指令重排序

现代的处理器会对某些指令进行重叠执行(采用指令级并行技术(Instruction-Level Parallelism,ILP),亦或者在不影响执行结果的情况下会将Java字节码对应的机器码指令进行顺序调换以提高单线程下代码的执行效率,这种问题的表象和上述情况类似,这里也就不再演示了。

4.内存系统重排序

该方式排序并不是真正意义上的重排序,在JMM上常常表现为主存和本地内存的数据不一致。

5.如何避免指令重排序

这一点其实在上述各种重排序都已经简单的说明了,对于编译器,会禁止特定类型的编译器重排序来避免编译器重排序在多线程情况下带来的问题。对于指令重排序即处理器重排序,JVM生成程序指令序列时,会根据情况插入特定的内存屏障(Memory Barrier)来相关指令来告知处理器避免特定类型的指令重排序。

二、详解Java内存模型JMM

1.什么是JMM模型

为了屏蔽不同操作系统之间操作系统内存模型的差异,Java定义了属于自己的内存模型规范解决这个问题。 JMM也可以理解为针对Java并发编程的一组规范,抽象了线程和主内存之间的关系,以类似于volatile、synchronized等关键字以解决并发场景下重排序带来的问题。

JMM规定所有示例对象都必须放置在主存中,所以每个线程需要操作这些数据时就需要将数据拷贝一份到本地内存中在进行相应的操作。

而每个Java将主存中拷贝的变量在完成操作后写回主存中会经历以下过程:

同时,JMM模型还规定这些操作还得符合以下规范:

2.JVM和JMM有何区别(重点)

JVM规定了运行时的区域划分,例如实例对象必须放置在堆区等。 而JMM则决定了线程和和主内存之间的关系,例如共享变量必须存放在主内存中。通过定义一系列规范和原则简化用户实现并发编程的种种操作且确保Java代码从编译到转为CPU机器码执行结果都是准确无误的,也就是说JMM是一种内存模型语义的抽象并非实际的内存模型。

3.什么是happens-before原则?常见的happens-before原则有哪些?

happens-before也是一种JMM内存模型用来阐述内存可见性的一种规约,对应的happens-before原则共有8条,而常见的有以下5条:

对于不会影响单线程或者多线程指令重排序操作不做要求,即不会过分干预编译器和处理器的大部分优化操作,例如下面这段代码,在单线程情况下,因为两者声明没有任何关联,处理器为了提高程序执行的并行度完全可以不管任何顺序任意执行,这也就是我们常说的as-if-serial,即没有强关联的指令,处理器可以根据自己的优化算法执行,任意重排序,对外结果好像就是串行执行一样:

而对于某些场景, JMM对于编译器或处理的某些会影响指令重排序的操作进行禁止,如下所示,getOne和getTwo先于最后计算,计算依赖于前两个变量,操作即两个get操作happens-before于最后的计算,但是两个get操作没有强关联,所以JVM这两段代码进行指令重排序的时候,JMM是允许的,所以执行时getTwo可能会先于getOne执行。

与之相反就是最后的计算,因为依赖于前两个get,所以JMM模型是明确要求禁止这种情况,于是就提出了happens-before原则,即写前面的变量happens-before于后面的代码以及A happens-before B,B happens-before C,那么A happens-before C,按照我们的例子就是每一个get操作都会按照顺序写,因为1操作先于2先于3,所以最终执行顺序就是1、2、3:

 public static void main(String[] args) {
        int one = getOne();//1
        int two = getTwo();//2
        System.out.println(one + two);//3
    }

    private static int getOne() {
        return 1;
    }

    private static int getTwo() {
        return 2;
    }

4.happens-before和JMM有什么关系

JMM原则和禁止重排序的遵循的准则都是基于 happens-before准则要求,也就是要求针对编译器的指令重排序必须根据该准则通过某种方式落实,最常见的方式就是在生成执行指令前插入内存屏障让处理器知晓那些指令不可重排序来解决问题,由此实现程序员只需理解happens-before原则的抽象即可理解可见性,由此避免底层编译器和处理器具体的实现:

5.JMM规范如何解决处理器指令重排序问题

为了保证内存可见性,编译器在生成指令指令序列时通过内存屏障指令来禁止特定类型的处理器重排序问题,对应的屏障指令有:

所以对于多核CPU对彼此内存操作不可见导致数据错乱,我们可以直接通过storeload指令来解决该问题:

来源:写代码的SharkChili内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯