当相邻的两行代码没有关联的时候,CPU可能会进行指令重排序,对程序进行优化执行。
1.以下代码中启了两个线程,线程1执行a=1x=b,线程2执行b=1y=a。
2.a=1和x=b是不相干的两行代码,因此CPU可以对这两个指令进行重排序。同理,b=1和y=a也可以指令重排序。
3.假如CPU完全按代码顺序执行,那么可能出现这么几种情况:x=0y=1x=1y=0x=1y=1。不可能出现x=0y=0。
4.我们的代码会不断的循环执行,当x=0y=0的时候退出循环。
4.然而实际情况如下图所示,当程序执行了12万次,出现了x=0y=0的情况,证实了CPU的指令重排序。
指令重排序,可能会给我们的应用造成一定的问题。例如单例模式中的DCL(double check lock),采用了这种加锁模式的代码,如果不设置instance为Volatile,那可能导致线程取到的实例并未完全初始化完毕,可能造成问题。
当线程在new instance的时候,并非原子操作,包括多个步骤,例如给成员变量赋值、将引用指向堆内存的对象,假如这两个步骤发生了指令重排,正好有另一个线程执行的时候,判断instance是否为空,发现不为空,则直接返回该instance,用instance中的未初始化的成员变量去做业务逻辑,那么就可能出现问题。所以Volatile关键字在这里的作用是为了禁止指令重排序,防止线程获取instance的时候,取到的是未赋值完毕的中间态的对象。