今天就和大家一起回顾一下这些知识点的联系和理解。Java内存模型网上关于Java内存模型的内容很多,其中很多讲的是多CPU和缓存之间的数据一致性,所以顺带提出了MESI等缓存一致性协议。其实这里是没有问题的,挺合乎逻辑的。但是为什么会有Java内存模型呢?为什么会有happens-before原则呢?这些内容基本上都没有说清楚,让人很是迷惑。另外,有的还拉出内存障碍和执行时序问题,但是没有逻辑,听上去很乱。曾经我花了一个通宵仔细阅读了一篇很火的文章,但最后没看懂。对于Java内存模型,我舍弃了一些不必要的细节,整理了一些自己的理解。感觉还是比较容易理解的。首先,由于多核CPU和缓存的存在,存在缓存一致性问题。这个问题属于硬件层面的问题,解决方案是各种缓存一致性协议。不同的CPU使用不同的协议,MESI是最经典的缓存一致性协议。其次,操作系统作为底层硬件的抽象,自然需要解决CPU缓存与内存之间的缓存一致性问题。各个操作系统抽象出CPU缓存和高速缓存的读写访问过程,最终归结为“内存模型”。从硬件到操作系统,这是我自己的理解,没有找到任何资料提到这个。但我认为这应该没有错。因为操作系统是对底层硬件的抽象,所有抽象的东西都需要定义一些概念。对于操作系统,这些概念是内存模型、CPU时间片等。内存模型这个词在操作系统的教科书上也能找到,这也是有据可查的。那么,我们是从硬件层面来理解操作系统层面的,但这跟Java内存模型有什么关系呢?最后,Java语言作为运行在操作系统层面的高级语言,为了解决多平台运行的问题,在操作系统的基础上进一步抽象,Java语言层面的内存模型是获得。一致性问题。我们之所以创建Java内存模型,是因为要在Java语言中实现“WriteOnce,RunAnywhere”的理念,所以必须解决多平台内存模型不一致的问题。Java内存模型规定了很多规则。如果一个Java程序能够遵守Java内存模型的规则,那么它编写的程序就是并发安全的。这是Java内存模型的最大价值。至此,我们从硬件、操作系统到语言层面都知道了Java内存模型诞生的原因。我们知道它的诞生是为了解决统一多平台内存模型的问题,更进一步,其实就是多线程数据一致性的问题。前面在happens-before原则中提到,为了解决多平台内存模型的统一和多线程的数据一致性,出现了Java内存模型。但是Java内存模型的内容太多了,基本记不住,程序员理解起来非常困难,所以就有了happens-before原则。所以happens-before原则是对Java内存模型的一种简化,让我们可以更好的编写并发代码。volatile关键字volatile关键字其实和Java内存模型有关,但是很多文章都没有说清楚。volatile关键字有两个作用,即可见性和禁止指令重排序。但是它为什么会有这两个功能呢?实际上,volatile的这两个函数的来源都来自于Java内存模型中为volatile变量定义的特殊规则。这就是volatile关键字和Java内存模型的关系,比较简单。至于记忆障碍这个词,其实是一个让我们很容易理解的名词。它诞生于volatile禁止指令重排序的功能,没有什么难理解的。synchronized关键字synchronized关键字也常用于并发编程。其实和Java内存模型无关,而是和Java虚拟机规范有关。synchronized关键字编译后,会在同步块前后形成两条字节码指令monitorenter和monitorexit。这两个字节码的执行需要指定一个对象被锁定或解锁。monitorenter和monitorexit这两条字节码指令之所以能实现这样的功能,是因为Java虚拟机中有强制定义,需要虚拟机去实现。synchronized关键字还与Java对象的内存布局有关。自旋锁、自适应锁、偏向锁,它们的实现都是通过Java对象中的对象头来判断,然后进行一系列的逻辑操作。综上所述,我们基本上可以理清Java并发编程中常用概念之间的关系。Java内存模型是对内存布局的一种抽象,解决了多平台运行和多线程一致性的问题。happens-before原则是对Java内存模型定义的一种简化,方便我们学习。Volatile是一种轻量级的同步机制,它来源于Java内存模型赋予的权利。synchronized关键字的合法性来自Java虚拟机规范。在synchronized中,自旋锁、自适应锁、偏向锁等,都是靠Java对象的对象头来判断的。以上是我对Java并发编程中常用概念的理解,感觉比较清晰。
