Java内存模型规定了在多线程程序中,什么样的行为是容许出现的,什么样的行为是禁止出现的。这样说可能有点抽象,咱们换一个角度。将程序行为抽象成读操做和写操做,每一个线程有本身的局部变量,同时线程之间还存在共享变量。那么一个多线程程序执行结束后,全部变量会有一个最终值。Java内存模型来决定什么样的值合法,什么样的值不合法。html
内存模型不能要求的太严格,这样会阻碍不少优化方法,下降程序执行的效率,但也不能要求的太松,由于这样会致使一些执行结果违反咱们的直觉。例如指令间的重排序问题,若是线程内部的指令彻底按照程序中指明的次序执行,而且每次执行一条指令,执行的结果当即生效,那么就会阻碍不少优化方法,但这样对程序员是有好处的,由于程序员很容易推断程序的执行结果,这样写出的程序就容易与本身的意图一致。这种内存模型被称为顺序一致性模型(Sequential Consistency)。反之,若是为了优化程序执行效率,重排序的可能性有不少,那么程序的效率是提升了,但对程序员来讲,就很难推断程序的执行结果。这一类的内存模型被称为Relaxed Memory Model。java
这样,咱们就遇到了一个两难的问题:git
而程序的效率,与程序是否容易写对都很重要。为了解决这个问题,科学家提出了 Data Race Free 的概念,它是对多线程程序同步程度的一种描述,基本的思想是若是多线程程序进行了正确的同步,那么程序员就能够按照顺序一致性模型去推断程序的执行结果,而底层对内存操做的实现,能够按照 Relaxed Memory Model进行优化。程序员
Java 内存模型包含了两方面的内容github
其中第一方面是与 Data Race Free相关的,第二方面与后面介绍的 Causality Requirements 相关。安全
Java 内存模型其实定义了好几个概念来讲明什么是正确的同步。markdown
若是存在多个线程,同时访问同一地址,而且至少有一个是写操做,那么这个程序存在冲突访问多线程
两个操做之间若是知足下面任意一个条件,就能够说这两个操做之间存在 happen-before order:并发
其中有些我也不是很理解。。oracle
全部存在冲突访问的操做之间都有 happen-before order,那么此多线程程序知足 data race free
假如多线程程序在顺序一致性模型下执行,若是它知足 data race free,那么此程序进行了正确的同步。
正确同步的多线程程序,其执行结果与在顺序一致性模型下的执行结果一致。仔细体会下概念之间的关系。有点绕。
另外一方面,若是程序没有正确同步,执行结果也不是任意的,必须对其进行限制,但限制又不能太强,由于太强会阻碍优化。因此 Java 内存模型使用了 Causality Requirements 的概念。
为了精肯定义内存模型,Java语言规范中,提出了 Causality Requirements 的概念。不知道是什么缘由,这个概念不多被说起,可是我以为它是很重要的,但同时,也是很是使人费解的。语言规范中,首先定义了 Well-Formed Executions 的概念,如今对内存模型的不少讨论,都是在这一层,它包括了对多线程程序执行中,与锁,volatile变量,执行次序等等相关的规定。若是一个多线程程序的执行知足这些规定,那么这个执行就是 Well-Formed Executions 的。国内有一个系列文章《深刻理解Java内存模型》,主要是在这方面描述Java内存模型。此外,在 Java 并发领域内著名的 Doug Lea 也给出了一个 The JSR-133 Cookbook for Compiler Writers,为编译器做者们提供参考,探讨的也是这方面的问题。可是,内存模型对多线程程序的执行是否合法,不只仅要看它是不是 Well-Formed Executions,此次执行还须要知足 Causality Requirements。
语言规范中规定了一个构造过程,若是经过这个构造过程,能够构造出多线程程序最终的执行结果,那么此次执行就知足 Causality Requirements。构造过程从一个空集合C0开始,每次将其中添加若干操做,若是全部操做都能被添加,那么构形成功。即,
C0 -> C1 -> C2 -> ... -> C
其中 C_i 是 C_(i+1) 的子集。你可能注意到了,以前说的“操做能被添加”,什么叫操做能被添加呢?语言规范中规定了,每个 Ci 都对应一个 Ei,全部 Ei 都要知足 Well-Formed Executions。也就是说,若是你添加了操做后,对应的 Ei 不知足 Well-Formed Executions,那么这个操做就不能被添加。若是最终,你的多线程程序没法构造出这样一个执行链,那么,它的执行结果是非法的。
另外,Java 内存模型最初论文做者维护了一个页面 The Java Memory Model,其中有一个条目叫 Causality Test Cases,给出了一些小例子,以便人们明白哪些行为是知足 Causality Requirements 的,哪些是不知足的。此外,在 Java 并发领域内著名的 Doug Lea 也给出了一个 The JSR-133 Cookbook for Compiler Writers,为编译器做者们提供参考。不过听说这份规范有些地方要求太严格了,开发者们仍是根据Java语言规范和虚拟机规范来开发。
参考资料:Java 语言规范以内存模型