并发编程的3个源头问题分别是:html
Java内存模型就是为了解决可见性和有序性问题。java
缓存会致使可见性问题,编译优化会致使有序性问题。若是要避免这两个问题,最简单的方法不就是禁用缓存和编译优化。这样就丢掉了优化程序性能的有利武器,显然是不可取的。程序员
合理的方案应该是按需禁用缓存以及编译优化。什么叫按需禁用缓存以及编译优化呢?指的就是程序员在写代码的过程当中,对有可能出现并发问题的代码禁用缓存和编译优化。编程
Java内存模型就是禁用缓存和编译优化的一种规范,它规范了 JVM 如何提供按需禁用缓存和编译优化的方法。如今提到的 Java 内存模型,通常指的是 JDK 5 开始使用内存模型,遵循的是 JSR-133 描述的规范。缓存
JSR133Java内存模型是一个雄心勃勃的计划,它是编程语言规范第一次尝试合并一个可以在各类处理器架构中为并发提供一致语义的内存模型。不过,定义一个既一致又直观的内存模型远比想象要更难。JSR133 为Java语言定义了一个新的内存模型,它修复了早期内存模型中的缺陷。为了实现 JSR133,final和volatile的语义须要从新定义。架构
完整的语义见:http://www.cs.umd.edu/users/p...,可是正式的语义不是当心翼翼的,它是使人惊讶和清醒的,目的是让人意识到一些看似简单的概念(如同步)其实有多复杂。幸运的是,你不须要懂得这些正式语义的细节——JSR133的目的是建立一组正式语义,这些正式语义提供了volatile、synchronzied和final如何工做的直观框架。并发
—— Java内存模型FAQ(三)JSR133是什么?app
Java内存模型主要分红两部分,一部分面向并发编程的开发人员,一部分面向JVM开发人员,咱们须要关注的是前者。前者主要包括 volatile
、synchronized
和 final
三个关键字,以及六项 Happens-Before
规则。框架
Java内存模型是按需禁用缓存和编译优化的规则。Happens-Before 表示前面一个操做对后面一个操做是可见的,它约束了编译器的优化行为,编译器能够优化,可是须要遵循 Happens-Before 规则。编程语言
有这样 6 条和可见性相关的规范:
前面提到过,如今所说的 Java 内存模型通常指的是 Java1.5 以后的内存模型,它遵循 JSR-133 描述的规范。采用新的规范的缘由是旧的 Java 内存模型存在问题,好比:对 final 修饰的变量进行过分的编译优化,以及 volatile 的语义问题。
// 如下代码来源于【参考1】 class VolatileExample { int x = 0; volatile boolean v = false; public void writer() { x = 42; v = true; } public void reader() { if (v == true) { // 这里x会是多少呢? } } }
上面这段代码,变量 v 是一个 volatile 类型的变量,则会禁用缓存,全部线程对 v 的操做都是直接从内存中读取。此时,线程 A 执行 writer() 方法,则 v = true 会被写入内存;同时线程 B 执行 reader() 方法,显然会经过 if 判断,那么此时 x 的值会是多少?
在 Java1.5 以前,x 的值多是 0,也有多是 42。由于 x 有可能被 CPU 缓存起来,致使可见性问题。这显然不是咱们指望的状况,因此在新的 Java 内存模型中对 volatile 的语音进行了加强,就是依靠 Happens-Before 中的 volatile 变量规则和传递性规则。
如上图所示,线程 A 执行 writer() 方法,线程 B 执行 reader() 方法:
此时,经过 Happens-Before 规则对 volatile 变量的语义加强,线程 B 读到的 x 就必定是 42,而不会存在是 0 的状况,符合咱们对程序的期待。
JSR 133 (Java Memory Model) FAQ