Java内存模型详解

Java中内存模型的定义

Java中内存模型的定义在Java语言规范的第17章第4小结,原文定义如下:

A memory model describes, given a program and an execution trace of that program, whether the execution trace is a legal execution of the program. The Java programming language memory model works by examining each read in an execution trace and checking that the write observed by that read is valid according to certain rules.
The memory model describes possible behaviors of a program. An implementation is free to produce any code it likes, as long as all resulting executions of a program produce a result that can be predicted by the memory model.

中文描述如下:

对于一个特定的程序和这个程序的一个执行流程,内存模型描述了这个执行流程是不是合法的。Java编程语言内存模型通过检测一个执行流程中的读然后根据特定的规则检查被读观测的写是否有效。
内存模型描述了一个程序的可能行为。一个实现可以生成它所喜欢的任意代码,只要程序执行所产生的结果是可以被这个内存模型预测的。

例1. 没有正确同步的程序可能产生令人惊讶的行为
比如表A中的程序流程。这个程序使用了本地变量r1和r2,共享变量A和B。一开始,A == B == 0。
表A. 指令重排导致的令人惊讶的结果

Thread 1Thread 2
1: r2 = A;3: r1 = B;
2: B = 1;4: A = 2;

看起来r2 == 2和r1 == 1这个结果是不可能的。直观上看,不是指令1开始执行就是指令3开始执行。如果指令1开始执行,它不能看到指令4中的写操作。如果指令3开始执行,它不能看到指令2中的写操作。
如果这个结果(r2 == 2和r1 == 1)是成立的话,指令执行的顺序应该是:4 -> 1 -> 2 -> 3 。从表面上看,这是荒谬的。
然而,编译器允许重排每一个隔离线程中的指令,只要不影响那个线程的执行。如果指令1和指令2发生了重排,如表B所示,就可以很容易的看到结果(r2 == 2和r1 == 1)是怎么来的。

Thread 1Thread 2
2: B = 1;3: r1 = B;
1: r2 = A;4: A = 2;

对于一些程序员来说,这个行为看起来是错误的。然而,值得注意的是代码没有被正确的同步:

  • 每一个线程中都有一个写操作
  • 另外一个线程中对同一个变量的读操作
  • 读和写操作没有用同步排序

这是一个数据竞争的例子。当代码中存在数据竞争的时候,经常会导致反直觉的结果。
内存模型决定了在程序中的每个点可以读取什么值。每个隔离线程的行为受线程语义的控制,而内存模型决定了每一个读取的值。我们称这种情况下,程序遵循线程内语义。线程内语义是单线程程序的语义,线程内读取值的行为是完全可以预测的。为了判断执行中线程t的行为是否合法,我们简单地在单线程上下文中执行。
每一次线程t的执行产生了线程间的行为,必须遵照程序的执行顺序。如果是读的行为,线程t随后的执行将会使用这个值。

17.4.1 共享变量
在线程间共享的内存被称为共享内存或堆内存。
所有的实例字段、静态字段喝数组元素被存储在堆内存中。在这一章中,我们使用变量这一术语来来指代字段和数组元素。
本地变量、标准的方法参数和异常处理参数永远不会在线程间共享并且不受内存模型影响。
对同一个变量的两种访问方式(读或写)会发生冲突,如果其中一个访问方式是写。

由上述语句可以看出,内存模型实际上影响了线程间共享变量的访问方式。

17.4.2 行为
线程间的行为是一个线程产生的可以被另外一个线程监测到或直接被另外一个线程影响的行为。由如下几种程序产生的线程间行为:

  • Read(normal,or non-volatile).读一个变量
  • Write(normal,or non-volatile).写一个变量
  • 同步行为,如下:
    • Volatile read.
    • Volatile write.
    • Lock.
    • Unlock.
    • 线程的第一个和最后一个行为
    • 开启一个线程或检测一个线程已经终止的行为
  • 外部行为。

由于规范太长,在这个就不继续翻译了,详细的内容请参见原文。
很多人第一次看到内存模型自然而然的会认为内存模型是描述了对象在内存中的分布,其实并不是这个样子的。JVM运行时所占的内存区域在Java虚拟机规范的第2章第5小结中被定义,被称为运行时数据区
Java虚拟机定义了各种运行时数据区用于程序的执行。一些数据区在Java虚拟机启动的时候被创建,在Java虚拟机退出的时候被销毁。其它的数据区是和线程相关的。线程相关的数据区当线程被创建时创建,当线程退出时销毁。
Java内存模型其实是保证了多线程环境下内存访问的一致性,而运行时数据区描述了Java虚拟机运行时所需要的空间划分。
有了上面的认知以后,再看下面这篇文章就能理清作者的思路,否则会觉得很乱。
全面理解Java内存模型(JMM)及volatile关键字
内存屏障相关的内容也应该了解一些:
JMM——volatile与内存屏障
Java虚拟机规范和Java语言规范的下载地址:
Java Language and Virtual Machine Specifications

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java内存模型Java Memory Model,JMM)是Java程序在多线程环境下的内存访问规范。它定义了线程之间如何进行通信,以及线程如何与主内存和工作内存交互。根据引用\[1\]和引用\[2\]的内容,Java内存模型包括主内存和工作内存。主内存是所有线程共享的内存区域,而每个线程都有自己的工作内存,工作内存是线程私有的。线程之间的共享变量存储在主内存中,而每个线程在执行时会将共享变量从主内存复制到自己的工作内存中进行操作。引用\[3\]中提到,线程栈和堆主要分布在主内存中,有时部分线程栈和堆会分布在CPU寄存器和CPU缓存中。 Java内存模型还定义了一些同步操作和规则,用于保证多线程环境下的数据一致性和可见性。这些同步操作包括锁定、解锁、读取、写入等。通过这些同步操作和规则,可以确保线程之间的数据同步和正确的执行顺序。 总结来说,Java内存模型Java程序在多线程环境下的内存访问规范,它定义了线程之间如何进行通信,以及线程如何与主内存和工作内存交互。它是保证多线程程序正确执行的基础。 #### 引用[.reference_title] - *1* *2* *3* [Java内存模型](https://blog.csdn.net/m0_46485771/article/details/105711813)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值