1.基本概念
- 内存可见性:指线程之间的可见性,当一个线程修改了共享变量时,另一个行程可以读取到修改后的值。
- 重排序:为了优化性能,对原有的指令执行顺序重新排序,重排序可能发生在多个阶段,比如编译重排序、CPU重排序等。
- happens-before规则:是一个给程序员的使用规则,只要程序员遵循hanppens-before编码,JVM就能保证指令在多线程的执行顺序符合程序员的预期。
2.volatile的功能
- 保证变量的内存可见性;
- 禁止volatile变量和普通变量重排序。
2.1 volatile的内存可见性
当一个线程对volatile修饰的变量进行写操作时,JMM会把该线程对应的本地内存共享变量的值刷新到主内存中去。当一个线程对volatile修饰的变量进行读操作时,JMM会立即把本地内存对应的共享变量置为无效,从主内存中读取共享变量的值。
2.2 禁止重排序
主要是禁止普通变量和用volatile修饰的变量进行重排序。
JVM通过内存屏障来限制处理器的重排序。
内存屏障:分为读屏障(Load Barrier)和写屏障(Store Barrier).
内存屏障的作用:
- 阻止屏障两边的指令进行重排序;
- 强制把写缓存区/高速缓冲区中的脏数据写主内存中,
或者让缓存中相应的缓存失效(失效重新读取主缓存中的数据)
编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定的处理器重排序。编译器选择了JMM内存屏障插入策略。
屏障策略:
在每个volatile写操作之前插入StoreStore屏障;
在每个volatile写操作之后插入StoreLoad屏障;
在每个volatile读操作之后插入LoadLoad屏障;
在每个volatile读操作之后再插入一个LoadStore屏障。