自学内容网 自学内容网

简单了解JMM

什么是JMM

JMM是Java内存模型,是一种虚拟机规范,用于屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果,JMM主要考虑的就是各种变量的访问规则,对于JMM,把各种硬件抽象为本地内存和主存来存放变量。

image-20240318203150822

内存间交互操作

关于变量如何从主存拷贝到本地线程以及变量如何从本地线程同步到主存的细节,JMM定义了8中操作来完成,对于每个线程来说,只能操作本地内存的变量,规定read、load要顺序执行,store、write要顺序执行。

image-20240318205713894

操作系统的三大问题

在谈论JMM之前,首先我们需要了解操作系统的几个问题,JMM正是解决了操作系统这些问题。

随着时代的发展,计算机逐步更新换代,人们对于计算机的要求越来越高,对于家庭或者公司的电脑需要人机交互,这就要求计算机需要有较短的响应时间,为此工程师引入了CPU的多级缓存、时间片轮转调度算法、指令优化重排,但是也相应的带来了问题:CPU缓存一致性问题(可见性)、代码被多个线程访问的并发问题(原子性)、指令没有按照程序员的意愿执行(有序性)。

JMM抽象的问题

可见性:线程本地变量和内存的可见性问题,规定线程只能操作本地内存变量,线程对内存的修改无法及时被其它线程看到

原子性:如 i++ 语句,底层由多条指令组成,CPU实际执行的是指令,在指令执行期间可能会发生时钟中断切换线程,最终导致程序执行结果出问题

有序性:如 Java 创建对象过程,类加载 -> 实例化 -> 初始化 -> 引用赋值,由于指令重排可能导致引用赋值在初始化之前,导致其它线程使用到未初始化的对象

Java代码如何解决问题

  • 可见性:

    • 可通过volatile关键字解决

    • 可通过synchrinized关键字解决

    • 可通过final关键字解决

  • 原子性:可通过synchrinized关键字解决,底层是通过monitorenter和monitorexit字节码指令。

  • 有序性:

    • 可通过volatile关键字解决,给字节码中加入了内存屏障

    • 可通过synchrinized关键字解决

Happens-Before原则

如果JMM中所有的有序性仅靠volatile和synchronized来完成,未免很多操作有点啰嗦,我们在日常编码的过程中并不会过多关注有序性,因为有个Happens-Before原则来辅助保证代码操作的顺序性。

常见的Happens-Before原则:

  • 程序次序规则:同一个线程内,对于顺序执行,前面的操作先行于后面的操作

  • 管程锁定规则:对于一个锁,unlock先行于lock

  • volatile规则:对于一个用volatile修饰的变量,写操作先行于读操作

  • 线程启动规则:start()先行于这个线程的其它动作

  • 线程终止规则:线程所有动作先行于终止检查

  • 线程中断规则:interrupt()先行于检测到中断事件的发生

  • 对象终止规则:对象的初始化完成先行于销毁

  • 传递性:A操作先行于B操作,B操作先行于C操作,那么A操作先行于C操作

如下面这个程序,你不能保证 i = 1 一定会在 j = 2 前执行,但是这也不影响Happens-Before原则的正确性,因为这并不影响整个程序执行结果的正确性。

 int i = 1;
 int j = 2;

原文地址:https://blog.csdn.net/xtrans/article/details/136822357

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!