在网上很多资料都介绍了java内存模型的内容,可看的资料越多,导致自己越迷糊了,到底什么是Java内存模型,Java内存模型是用来干嘛的,接下来就和大家一起探讨Java内存模型到底是个啥?
说到Java内存模型,先得介绍一下什么是模型。拿最简单的小时候玩的飞机模型来说,它让我们了解了什么是飞机,飞机大概是个什么样的,它的机舱在哪,驾驶室在哪等等...
理解了这一点,相信你对模型就基本上有一个大概的了解了。那么我们接下来就开始介绍什么是内存模型。同样的,内存模型是用来抽象对计算机内存进行操作的一个理想化的概念。
首先介绍一个理想化的内存模型,这也是程序员最期待看到的一个内存模型 - 顺序一致性内存模型。这个内存模型的概念比较简单,即我们写了一段程序(图1-1),我们期待程序按照我们的写的内容执行,即先执行第1步,接下来依次执行2、3、4步,这就是最简单也是最理想化的模型,顺序一致性内存模型,这种模型更容易理解,我们在写代码时执行的过程中,能“看”到的也是这种理论化的模型的执行结果。
顺序一致性内存模型为程序的开发者和使用者提供了方便,但是,对于计算机而言,它却限制太多,以至于使计算机的性能不能充分发挥。相对于我们看到的顺序一致性模型而言,计算机更倾向于“优化”我们代码的执行顺序,如图1-1中,第3步依赖于第1步和第2步的执行结果,但是第1步和第2步本身没有依赖关系,因此,计算机内存在读写的过程中,就可能先执行第2步,然后执行第1步。也就是说,计算机基于单线程程序中不改变程序的运行结果,来对我们代码的执行顺序进行优化。
那么计算机是如何优化我们的程序呢?
在讨论计算机如何优化之前,我们首先要知道我们的程序对内存主要做了什么操作:读和写。
因此,计算机针对内存的读和写对我们的程序进行如下优化:
1)写/读操作的优化:两个不存在依赖关系的写/读操作可以进行执行顺序的优化
2)写/写操作的优化:两个不存在依赖关系的写操作可以进行执行顺序的优化
3)读/写和读/读操作的优化:两个不存在依赖关系的读/写或读/读操作可以进行执行顺序的优化
首先介绍写/读的优化。大部分内存模型几乎都会进行这种优化,简单理解方式为,写比读更消耗资源,因此,大部分的内存模型都会将写操作和读操作的执行顺序进行优化(前提是写/读操作不存在依赖关系)【本质上是因为计算机使用了写缓存,因此,进行写/读的优化能大幅度提升计算机的执行效率】。如图1-2中,第1步和第2步为写操作,第3步为读操作,计算机在执行过程中执行完第1步之后,可能会先执行第3步(读),再执行第2步(写),这就是最基本的写/读重排序(变为了读/写)。
接下来介绍写/写操作的优化。写写操作的优化比较容易理解,如上图1-2中,由于第1步和第2步本身并没有依赖关系,因此,内存在写入过程中,可能会先执行第2步,再执行第1步,这就是写/写操作的优化。
最后介绍读/写和读/读操作的优化。内存在读取变量和写入变量的过程不存在依赖关系时,如内存先读取a的值(第1步),然后再写入b的值(第2步),由于这两步本身没有依赖关系,因此内存可能会先执行第2步,再执行第1步。读/读操作的优化类似【内存读取a的值(第1步),然后读取b的值(第2步),由于1,2两步没有依赖关系,因此,计算机可能会重排序为先执行第2步,再执行第1步】。
以上就是有关Java内存模型对于读写操作的优化了,针对这四种优化类型,整理了几种抽象的内存模型如下:
1)对于写/读操作放松的内存模型:Total Store Ordering(简称TSO)
2)在上一条基础上,对于写/写操作放松的内存模型:Partial Store Ordering(简称PSO)
3)在前两条基础上,对于读/写和读/读放松的内存模型:Relaxed Memory Ordering(简称RMO)和powerPc
几种内存模型和他们对于读/写重排序的支持如下(图1-3)
在单线程程序中,不论是哪一种内存的优化都不会影响最终结果的呈现,这也是内存模型建立的最基本原则,但是到了多线程程序中,由于各个线程间的操作相互不可见,因此,就可能会出现类变量读/写的问题,具体问题,我们在下一章,并发编程之内存间的“通话”一章中详细介绍。