本文开始死磕JMM(Java内存模型)由于知识点较多,分来写 该文为JMM第一篇 技术往往是枯燥的,本文文字较多 目前是JMM第一章,文末有惊喜
其实JMM很好理解,我简单的解释一下,在Java多线程中我们经常会涉及到两个概念就是线程之间是如何通信和线程之间的同步,那什么是线程之间的通信呢,其实就是两个线程之间互相交换信息线程之间通信的方式共有两种:一种就是共享内存,和消息传递
。在共享内存中的并发模型中线程是通过读取主内存的共享信息来进行隐性通信的。在消息传递通信中线程之间没有公共的状态,只能通过发送消息来进行显性通信。然而这只是线程通信,那么同步呢,同步就是在多线程的情况下有顺序的去执行。在共享内存中同步时显式进行的,在代码中我们必须要去指定方法需要同步执行比如说加同步锁等。在消息传递的并发模型中发送消息必须是在消接收之前,所以同步时隐式的。
java内存模型其实可以说是Java并发内存模型,在Java中是采用的共享内存模型的方式,所以Java线程之间的通信是隐式进行的,对我们是完全透明的,如果你不了解通信机制的话会产生各种线程可见性的问题。其实在Java中所有的静态域,域和数组元素都存在堆内存中,堆内存在线程中是共享的一般我们都称之为共享变量,局部变量,方法定义参数和异常处理参数不会在线程中共享,所以不会存在线程可见性的问题。上面我就说过线程之间的通信是由JMM来进行控制的,JMM来决定了一个线程操作了共享变量后如何对另一个线程可见。从上面所说的概念来看的话,JMM定义了线程与主内存的关系。
其实这样做的原因就是Java是跨平台语言,在个操作系统中内存都有一定的差异性,这样就造成了并发不一致,所以JMM的作用就是用来屏蔽掉不同操作系统中的内存差异性来保持并发的一致性。同时JMM也规范了JVM如何与计算机内存进行交互。简单的来说JMM就是Java自己的一套协议来屏蔽掉各种硬件和操作系统的内存访问差异,实现平台一致性达到最终的"一次编写,到处运行",说了这么多,JMM到底是怎么控制的呢?然后如何通信的呢?我们继续往下看。
JMM是一个抽象的概念,并不是真实的存在,它涵盖了缓冲区,寄存器以及其他硬件和编译器优化。
Java内存模型抽象图如下:
从上图可以看出每个线程都有一个本地内存,如果线程想要通信的话要执行一下步骤:
再看下面的这个图,表示了A如何向B发送消息
假设这时候有一个共享变量X默认值都是为0,那么线程A把X的值修改为1,这时候如何才能同步到B线程呢。
如果A线程把X修改成1之后,A线程会把X从A的本地内存中写入到主内存中,这样的话主内存的X就等于1了,这时候B线程就会去读取主内存的X变量,存入B的本地内存中,这样B线程的X变量值也就会变成了1。这样对吗。那现在如何通信我是知道了关键它究竟是如何来实现的,就是如何来实现通信的呢?
上面所说的步骤其实就是实现了线程之间的通信,但是不要以为线程之间的通信就是这么简单的,其实在Java中JMM内存模型定义了八种操作来实现同步的细节。
所以看似简单的通信其实是这八种状态来实现的。
同时在Java内存模型中明确规定了要执行这些操作需要满足以下规则:
所以上面说的操作要严格执行。