在学习 volatile 关键字的时候,我们都知道他有两个作用:1. 内存可见性;2. 禁止指令重排序。但是我们一般都是说,那么怎么证明呢?请看下面这段代码:

package cn.bridgeli.demo;

/**
 * @author Bridge Li
 * @date 2020/7/4 10:27
 */
public class Disorder {

  private static int x = 0;
  private static int y = 0;
  private static volatile int a = 0;
  private static volatile int b = 0;

  public static void main(String[] args) throws InterruptedException {
    int i = 0;
    for (; ; ) {
      i++;
      x = 0;
      y = 0;
      a = 0;
      b = 0;
      Thread one = new Thread(new Runnable() {
        @Override
        public void run() {
          a = 1;
          x = b;
        }
      }, "one");

      Thread two = new Thread(new Runnable() {
        @Override
        public void run() {
          b = 1;
          y = a;
        }
      }, "two");

      one.start();
      two.start();
      one.join();
      two.join();

      if (0 == x && 0 == y) {
        System.out.println("第 " + i + " 次(" + x + ", " + y + ")");
        break;
      }
    }
  }
}

如果仔细分析这段代码,我们就会发现,如果 CPU 没有乱序执行,那么无论任何时候 x 和 y 都不可能同时为零,但是事实上,这段代码是有可能出现 x 和 y 同时为零的,具体大家可以自己测试,需要说明的时候,什么时候指令重排了,要看运气,可能很快出现,也可能要等一会。

不过需要说明的是,实际上 CPU 的乱序执行,说的是指令级别的乱序执行,也就是:

Object o = new Object();

编译成字节码会有多条指令,例如实例化、初始化、o 指向申请的内存空间等等,而初始化和 o 指向申请的内存空间是可以乱序执行的,所以这也是 DCL 单例锁要加 volatile 关键字的原因。

最后简单说一下 volatile 是如何做的禁止指令重排

Java 内存模型其实是通过内存屏障(Memory Barrier)来实现的,Java 内存模型的重排规则会要求 Java 编译器在生成 JVM 指令时插入特定的内存屏障指令,通过这些内存屏障指令来禁止特定的指令重排序。在 hotspot 中的实现,在 bytecodeinterpreter.cpp 源码中有这么一段代码:

int field_offset = cache->f2_as_index();
if (cache->is_volatile()) {
  if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
    OrderAccess::fence();
  }
 }

具体到 orderaccess_linux_x86.inline.hpp 源码中:

inline void OrderAccess::fence() {
  if (os::is_MP()) {
    // always use locked addl since mfence is sometimes expensive
    #ifdef AMD64
      __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");
    #else
      __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
    #endif
  }
}

也就是通过 lock addl 指令锁北桥总线,实现禁止指令重排

参考资料:马士兵教育,多线程与高并发