首先,确保内存模型与多线程相关是一个大前提。 本文介绍了多线程与内存的关系。
实际上,内存模型对单线程来说,只是确保程序在单线程运行时会得到正确的结果。
另一方面,什么是存储器模型?存储器模型是对存储器读写访问过程的抽象。 这也可以说是内存模型定义了正确的内存读写行为(单线程)。 二、什么是排序? 排序是指更改语句或指令的顺序,以提高程序的执行性能。
如果编译器对:进行排序时程序在单线程上的执行结果不变,则可以更改语句的执行顺序。
处理器重新排序:可能会导致内存加载和存储看起来很无序,因为处理器使用缓存、缓冲等技术。
三. as-if-serial语义是什么? 无论怎么排序,单线程程序的执行结果都不会改变。
四、几种内存模型的比较顺序一致性内存模型是理论内存模型,处理器内存模型和Java内存模型都在此基础上进行了不同程度的弱化。
目的是提高程序的执行性能。
4.1、顺序一致性内存模型4.1.1、顺序一致性内存模型的一般含义是多线程的程序执行应该与多个线程在一个处理器核上交替执行的效果一致。
4.1.2、禁止顺序一致性内存模型特征编译器优化。 (单线程)按程序顺序依次访问存储器。
禁止处理器优化:每个写操作都立即通过内存显示。
4.1.3、内存模型与多线程的关系
图4-1-1
作为一例,说明逐次一致性存储器模型
图4-1-2
这有一些执行路径和可能的结果
第一个
第二类
第三个
(第四个(不可能的结果) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) 65 )
图4-1-3从图4-1-2的示例中,可以很快看到一些执行路径和结果。 可能的执行路径和结果在图4-1-3中明确列出。 那为什么第四种情况在顺序一致性内存模型中不可能发生?
由顺序一致性内存模型的特点决定,顺序一致性内存模型禁止处理器重新排序,没有第四个执行结果。 在什么要求下会出现第四种情况? 那是迎接
接下来,介绍处理器内存模型。
4.2、处理器内存模型处理器内存模型是基于顺序一致性内存模型放松一个或多个操作顺序(写入、写入、读取、读取、写入)而制成的内存模型。
注意:此处的放松意味着您可以对读写、写、读和写操作中的一个或多个操作进行排序。
下面用TSO的处理器内存模型进行说明
TSO存储器模型是在序一致性存储器模型的基础上通过放松写入读出操作的排序(排序)而生成的存储器模型。
4.2.1、内存模型与多线程的关系现代处理器都使用写缓冲器,因此现代处理器都允许通过写读操作进行排序。
图4-2-1
示例:
图4-2-2
TSO除了上述顺序一致性内存模型生成执行路径和结果外,还具有特定于TSO的执行路径和结果
该图左图引用于Sequential Consistency TSO文章中,右图引用于深入理解Java内存模型(1) ——的基础上
该图左图引用于Sequential Consistency TSO文章中,右图引用于深入理解Java内存模型(1) ——的基础上
图4-2-3
在图4-2-2的例子中,可能发生的执行结果如图4-2-3所示。 从图4-2-3可以看出,这是由于处理器内的执行顺序和存储器访问顺序不一致而发生的结果,这是由处理器的存储器系统进行的重新排列。
那么,接下来要说明的Java内存模型起什么作用?
问题:
1、编译器的排序与处理器可以通过写、读进行排序有什么不同?
2、编译器进行读取顺序的变更,但是在TSO的存储器模型中不允许变更读取顺序的情况下,在两者之间产生矛盾。
4.3、Java内存模型它描述了一系列规则或规范,它定义了一个线程向共享变量的写入何时看起来像另一个线程。
涵盖缓存、写缓冲区、寄存器以及其他硬件和编译器优化
4.3.1、内存模型与多线程的关系如图4-3-1所示,Java
该图参照了深刻理解Java内存模型的文章中的图
图4-3-1该图引用深刻理解Java存储器模型文章中的图
4.3.2、已正确同步的程序、未正确同步的程序或未同步的程序未同步的多线程程序
编译程序
类演示1 {
int x=0;
int y=0;
公共语音写入(
y=1;
int r1=x;
}
公共语音读取() }
x=2;
int r2=y;
}
}
可能的执行路径和结果:
图4-3-2
处理器
上述处理器存储器模型的示例
,产生的执行路径和结果正确同步的多线程程序
编译器:
class Demo1 {
volatile int x = 0;
volatile int y = 0;
public void write() {
y = 1;
int r1 = x;
}
public void read () {
x = 2;
int r2 = y;
}
}
Sparc-TSO处理器:Sparc-TSO处理器使用的内存模型是TSO(上文所讲的)
示例
图4-3-4通过在定义x和y变量时,加一个volatile修饰符。在最终执行的指令序列中会在S1和L1,S2和L2之间分别添加一个StoreLoadBarrier内存屏障。最终达到下图效果。
图 4-3-5
右边线程与左边的处理器在这里是一致的
这使得指令在执行顺序与在内存中的执行顺序一致
处理器中执行顺序:A1:S1 => A2 => A3:L1 内存中执行顺序: A1:S1 => A3:L1java内存模型控制线程对内存的访问
结论:正确同步Java内存模型的多线程跟顺序一致性的内存模型的执行路径是一致的。正确同步多线程+Java内存模型 == 顺序一致性的内存模型。
4.3.3、Java的内存模型对程序员是透明的Java的内存模型是对程序员是透明的,那Java内存模型是已什么方式呈现给程序员,
Java内存模型是已happens-before方式呈现给程序员的。
4.3.4、happens-before规则概念
后一个语句执行需要依赖前一个语句的执行结果,且前一个语句按顺序排在后一个语句的前面。但并不意味后一个语句一定在前一个语句之后执行。
int a = 1;
int b = 2;
int c = a + b + 1;
执行路径
图 4-3-6
程序如果能优化,编译器和处理器会尽可能的进行优化(即是提高性能)。
几个规则
程序顺序规则、监视器锁的规则、volatile变量规则、传递性等,具体含义可以参照SR-133: Java Memory Model and Thread Specification、深入理解 Java 内存模型的系列文章等文章。
4.3.5、解决什么问题它保证内存一致性,对程序员是透明的,它是通过解决重排序问题来保证的
它能禁止某种特定类型的编译器重排序
它能禁止某种特定类型的处理器重排序
通过内存屏障来禁止处理器重排序。在生成最终指令的序列过程中插入内存屏障(在使用同步原语(lock,volatile等)适当的位置插入)。
并不是对所有的处理器重排序都禁止,它只是禁止某种特定类型的重排序。
4.4、Java内存模型、处理器内存模型和顺序一致性内存模型关系顺序一致性内存模型是一个理论的内存模型。处理器内存模型是参照顺序一致性内存模型进行弱化的实现。
参考文档
1、深入理解 Java 内存模型的系列文章
2、wikipedia顺序一致性
3、CPU cache结构和缓存一致性(MESI协议)
4、CPU系统架构,cache miss终于明白点了
5、Sequential Consistency&TSO
6、内存模型和缓存一致性协议入门
7、JSR-133: Java Memory Model and Thread Specification