天天看点

JMM:Java内存模型

1.什么是 JMM

JMM 全称是 Java Memory Model. 

导致可见性问题的根本原因是缓存以及重排序。

JMM 实际上就是提供了合理的禁用缓存以及禁止重排序的方法。所以它最核心的价值在于解决可见性和有序性。

JMM 属于语言级别的抽象内存模型,可以简单理解为对硬件模型的抽象,它定义了共享内存中多线程程序读写操作

的行为规范:在虚拟机中把共享变量存储到内存以及从内存中取出共享变量的底层实现细节通过这些规则来规范对内存的读写操作从而保证指令的正确性,它解决了 CPU 多级缓存、处理器优化、指令重排序导致的内存访问问题,保证了并发场景下的可见性。

JMM 把底层的问题抽象到 JVM 层面,再基于 CPU 层面提供的内存屏障指令,以及限制编译器的重排序来解决并发问题。

2.JMM 抽象模型分为主内存、工作内存

主内存:是所有线程共享的,一般是实例对象、静态字段、数组对象等存储在堆内存中的变量。

工作内存:是每个线程独占的,线程对变量的所有操作都必须在工作内存中进行,不能直接读写主内存中的变量。

线程之间的共享变量值的传递都是基于主内存来完成。

Java 内存模型底层实现可以简单的认为:通过内存屏障(memory barrier)禁止重排序。

3.JMM 是如何解决可见性有序性问题的

JMM 提供了一些禁用缓存以及禁止重排序的方法,来解决可见性和有序性问题。

对程序提供的API关键字:volatile、synchronized、final;

4.JMM  如何解决顺序一致性问题

从源代码到最终执行的指令,可能会经过三种重排序:

JMM:Java内存模型

编译器重排序:JMM 提供了禁止特定类型的编译器重排序。

处理器重排序:JMM 会要求编译器生成指令时,会插入内存屏障来禁止处理器重排序。

并不是所有的程序都会出现重排序问题编译器的重排序和 CPU 的重排序的原则一样,会遵守数据依赖性原则,

编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。

5.HappenBefore(先行发生原则)

它的意思表示的是前一个操作的结果对于后续操作是可见的,所以它是一种表达多个线程之间对于内存的可见性。

JMM 中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作必须要存在 happens-before 关系。

这两个操作可以是同一个线程,也可以是不同的线程。

6.JMM  中有哪些方法建立 happen-before 规则

《深入理解Java虚拟机》中,有如下8条规则总结:

¨程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作

¨锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作

¨volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作

¨传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C

¨线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作

¨线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生

¨线程终结规则:线程中所有的操作都先行发生于线程的终止检测。

           我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行

¨对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始

继续阅读