聊聊我对Java内存模型的理解

简介:

所有的编程语言中都有内存模型这个概念,区别于微架构的内存模型,高级语言的内存模型包括了编译器和微架构两部分。我试图了解了Java、C#和Go语言的内存模型,发现内容基本大同小异,只是这些语言在具体实现的时候略有不同。

我们来看看Java内存模型吧,提到Java内存模型大家对这个图一定非常熟悉:

这张图告诉我们在线程运行的时候有一个内存专用的一小块内存,当Java程序会将变量同步到线程所在的内存,这时候会操作工作内存中的变量,而线程中变量的值何时同步回主内存是不可预期的。但同时Java内存模型又告诉我们通过使用关键词“synchronized”或“volatile”可以让Java保证某些约束:

“volatile” — 保证读写的都是主内存的变量
“synchronized” — 保证在块开始时都同步主内存的值到工作内存,而块结束时将变量同步回主内存

通过以上描述我们就可以写出线程安全的Java程序,JDK也同时帮我们屏蔽了很多底层的东西。

但当你深入了解JVM的时候你会发现根本就没有工作内存这个东西,即内存中根本不会分配这么一块空间来运行你的Java程序,那么工作内存到底是什么东西呢?

这个问题也曾经困扰了我很长时间,因为我从来没有从JVM的实现中找到过和主内存同步的代码,因为当使用“volatile”时我仅仅能从源代码中调用了这行语句:

__asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");

而这个指令在部分微架构上的主要功能就是防止指令重排,即这条指令前后的其它指令不会越过这个界限执行[注1]。

在现在的x86/x64微架构中读写内存的一致性都是通过MESI(Intel使用MESI-F,AMD使用MOESI)协议保证[注2],MESI的状态转换图如下:

更详细的中文文档描述可以查看这个文档:http://blog.csdn.net/zhuliting/article/details/6210921

那Java内存模型中所说的工作内存是什么呢?
我的理解是,首先“工作内存”是一个虚拟的概念,而承载这个概念主要是两部分:

1. 编译器
2. 微架构

作为编译器肯定是执行速度越快越好,所以作为编译器应当尽量减少从内存读数据,如果一个数据在寄存器中,那么直接使用寄存器中的值无疑性能是最高的,但同时这也会导致可能读不到最新的值,这里我们通过在Java语言中为变量加上“volatile”强制告诉编译器这个变量一定要从内存获得,这时编译器即不会做此类优化【案例见参考资料5(是一个.Net的例子)】。

对于微架构来说,在x86/x64下,CPU会在执行指令时做指令重排,即编译器生成的指令顺序和真正在CPU执行的顺序可能是不一致的。当我们用一个变量做信号的时候这种指令重排会带来悲剧,即如果有如下代码:

01 x = 0;
02 y = 0;
03 i = 0;
04 j = 0;
05 // thread A
06 y = 1;
07 x = 1;
08 // thread B
09 i = x;
10 j = y;

上面的代码i和j的值会是多少呢?答案是:“00, 01, 10, 11”都是有可能的。
对于这种情况,如果我们想得到确定的结果则需要通过“synchronized”(或者j.c.u.locks)来做线程间同步。

所以,我个人对Java内存模型的理解是:在编译器各种优化及多种类型的微架构平台上,Java语言规范制定者试图创建一个虚拟的概念并传递到Java程序员,让他们能够在这个虚拟的概念上写出线程安全的程序来,而编译器实现者会根据Java语言规范中的各种约束在不同的平台上达到Java程序员所需要的线程安全这个目的。

注1:关于“lock”前缀的详细说明可以查看这个文档《Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A: System Programming Guide, Part 1》的 这个章节“CHAPTER 8 MULTIPLE-PROCESSOR MANAGEMENT”。
注2:不同的微架构的内存模型都会有一些差别,本文中都是指x86/x64,如果想了解更多的微架构是如何处理的可以

目录
相关文章
|
4月前
|
存储 缓存 Java
2.什么是JAVA内存模型?
2.什么是JAVA内存模型?
43 0
2.什么是JAVA内存模型?
|
4月前
|
安全 Java
Java内存模型
Java内存模型 Java内存模型(Java Memory Model, JMM)是Java虚拟机规范中的一部分,定义了Java程序中多线程之间的内存访问规则。在多线程环境下,多个线程访问同一份数据时,可能会出现数据不一致或者未定义的行为,Java内存模型通过定义一些规则来保证多线程环境下的数据一致性。
|
9月前
|
存储 缓存 安全
Java内存模型JMM
计算机存储结构,从本地磁盘到主内存到CPU缓存,也就是从硬盘到内存,到CPU,一般对应的程序的操作就是从数据库查数据到内存然后到CPU进行计算 因为有这么多级的缓存(CPU和物理主内存的速度是不一样的) CPU的运行并不是直接操作内存而是先把内存里边的数据读到缓存,而内存的读和写操作的时候就会造成不一致的问题 JVM规范中试图定义一种java内存模型来屏蔽掉各种硬件和操作系统的内存访问差异 以实现让java程序在各种平台下都能达到一致的内存访问效果
48 0
|
12月前
|
缓存 自然语言处理 安全
java内存模型总结
在说java内存模型之前,先澄清下JVM内存结构与Java内存模型 JVM内存结构和Java虚拟机的运行时区域有关 Java内存模型和Java的并发编程有关 JVM内存结构,我们都知道java是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途。在《Java虚拟机规范jdk8》中说了JVM运行是内存区域结构可以分为6个区。 堆区 虚拟机栈 方法区 本地方法栈 程序计数器 运行时常量池 以上是java虚拟机规范,不同的虚拟机实现会各有不同,一般会准守规范 这里总结下,JVM内存结构由java虚拟机规范定义的
66 0
|
12月前
|
存储 缓存 Java
java内存模型JMM
Java内存模型(Java Memory Model,简称JMM),即Java虚拟机定义的一种用来屏蔽各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能够达到一致的内存访问效果的内存模型。本篇文章大致涉及到五个要点:1、Java内存模型的基础,主要介绍JMM抽象结构;2、Java内存模型中内存屏障;3、Java内存模型中的重排序;4、happens-before原则;JMM相关的三个同步原语(synchronized,volatile,final)。
86 0
|
存储 安全 Java
|
存储 算法 Java
|
存储 缓存 Java
Java内存模型(JMM)详解(2)
Java内存模型(JMM)详解
140 0
Java内存模型(JMM)详解(2)
|
缓存 Java 编译器
java内存模型
java内存模型
107 0
java内存模型
|
缓存 Java 编译器
java内存模型一
java内存模型一