材料来自 《Java高级程序员面试笔试宝典》第6.1.2节
1. 正常情况
CPU在运行期间会对指令进行优化,没有依赖关系的指令,他们的顺序可以被重排。在单线程执行下,发生重排是没有问题的,CPU保证顺序不一定一致,但结果一定一致。
如以下代码:
int i = 0; //(1)
i++; //(2)
boolean f = false; //(3)
f = true; //(4)
(1) 和 (3) 没有依赖关系,(1) 可能会排到(3)之后;而(1)和(2)有依赖关系,CPU一定会安排(1)早于(2)执行。
2. 异常情况
但在多线程环境下,重排序会引起很大问题,涉及线程安全的要素:有序性。
有序性:线程执行的顺序应当按照代码的先后顺序执行。
如下例子:
有成员变量:
int i = 0;
boolean f = false;
线程一执行代码:
Thread.sleep(10);
i++;
f = true;
线程二执行代码:
while(!f){
System.out.println(i);
}
理想结果是,线程二不断打印0,最后打印一个1,终止。
但实际上线程一中,f 和 i 没有依赖性,如果发生指令重排,那么 f=true 发生在 i++ 之前,就可能导致线程二在终止循环前的输出全都是0。
需注意这种情况并不常见,再次运行并不一定能重现,故很可能会导致一些莫名的问题。
如果修改上方代码,使用 volatile 来修饰 i 变量,就可以保证最后的输出符合预期。因为 volatile 修饰的变量,CPU 不会对它做重排序优化,故也保证了有序性。
版权声明:本文为B_Hopkins原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。