JMM(Java Memory Model)

指令重排
程序在经过编译器编译之后形成的指令序列会被CPU和编译器进行优化,提升执行效率。
as-if-serial语义
不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守 as-if-serial 语义。为了遵守 as-if-serial 语义,编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。
happens-before原则
JMM 可以通过happens-before
关系向程序员提供跨线程的内存可见性保证,即JMM对A happens-before B
保证A的执行结果对B是可见的。具体有以下原则:
程序次序规则: 无论如何重排,JMM保证一个线程内最终结果和代码顺序执行结果一致
锁定规则: 一个unlock操作要先行发生于对同一个锁的lock操作
volatile规则: 对一个变量写操作要早于对这个变量之后的读操作
传递规则
线程启动规则: Thread对象的start()方法先于发生对该线程的任何动作
线程中断规则: 对线程执行interrupt()肯定要优先于捕获中断信号
线程的终结规则: 线程所有操作要优先于线程死之前
对象终结规则: 一个对象初始化完成要先于finalize()方法之前
并发编程特性
- 原子性
JMM保证基本数据类型的变量读取赋值操作是原子性的,引用类型的变量读取和赋值操作也是原子性的。
- 可见性
volatile
,sychronized
和JUC
提供的显示锁都能保证可见性。volatile
保证共享变量读写都会在主内存中进行; 其他锁机制会保证锁释放之前会将变量的修改刷新到主内存中。
- 有序性
volatile
,sychronized
和JUC
提供的显示锁都能保证有序性。其中volatile
方式是禁止JVM和处理器对该关键字修饰的指令重排。
volatile
原理是汇编代码中使用lock修饰,这类似一个内存屏障,会导致以下结果: a) 将当前缓存行的数据写回到系统内存 b) 写回内存的操作会使在其他缓存了该内存地址的数据无效