前置概念

可见性

由于CPU寄存器和缓存的原因,本地内存与主内存(堆内存)并不是立刻同步的,这就造成可见性问题。

原子性

CPU层面不可中分割的代码或操作,不能被线程的中断。

临界代码区

被加锁的代码块

重排序

为优化程序性能,对原有的指令执行顺序进行优化重新排序。重排序可能发生在多个阶段,比如编译重排序、CPU重排序等。

happen-before

是一个给程序员使用的规则,只要程序员在写代码的时候遵循happens-before规则,JVM就能保证指令在多线程之间的顺序性符合程序员的预期。

什么是volatile

  • 保证变量的内存可见性(保证读写立即刷新到主内存,这个功能与锁作用的效果类似)

    Java内存可见性,volatile修饰的变量在进行写操作的时候,JMM会立刻把该线程的本地内存刷新到主内存中;当volatile修饰的变量在进行读操作的时候,会立刻让该线程本地内存无效,读取主内存的值。

示例代码,注意这里只有flag被volatile修饰,但a也被刷新到主内存中。

  1. public class VolatileExample {
  2. int a = 0;
  3. volatile boolean flag = false;
  4. public void writer() {
  5. a = 1; // step 1
  6. flag = true; // step 2
  7. }
  8. public void reader() {
  9. if (flag) { // step 3
  10. System.out.println(a); // step 4
  11. }
  12. }
  13. }

image.png

  • 禁止volatile变量重排序

分别对应两对内存屏障
volatile写—> 前普通写,后volatile读
volatile读—> 后普通读,后普通写
image.png