指令重排序
对单线程程序执行结果没有影响、虚拟机为优化和提升性能而对指令进行的一种重排序。例如:
int a,b,c=0;
a = 1;
b = 1;
c = a+b;
&
int a,b,c=0;
b = 1;
a = 1;
c = a+b;
结果是一样的。
但如果是在多线程中,em…,假设有一个加法:
假设有boolean flag = false;int a,b=0;
public int plus(){
if(flag == false){
a = 1;
b = 1;
flag = true;//说明a,b已经赋值
}
return a+b;
}
现在假定有A、B两个线程同时调用plus()方法。
注意:
在if块儿中,三个赋值操作可以交换,因为不影响最终的结果(对单线程来说),假设过程如下:
线程A | 线程B |
---|---|
flag==false | |
a=1 | |
flag = true | a+b |
b=1 | |
a+b | |
结果为2 | 结果为1 |
这显然违背了指令重排序的初衷,说明其在多线程中不适用。大家以后写多线程一定要注意这个问题。
单例模式中的DCL(double checked locking)
public class DCL{
private static DCL s;
private DCL(){
}
public static DCL getInstance() {
if(s==null) {
DCL sl;
synchronized(DCL.class) {
sl = s;
if(sl == null) {
synchronized(DCL.class) {
if(sl == null)
sl = new DCL();
}
s = sl;
}
}
}
return s;
}
}
这是修订过够的DCL,getInstance()方法中尝试引入第二个DCL变量以及第二次加锁解决指令重排序带来的问题。但注意在第二个if块儿中,同步语句块和赋值语句s = sl仍然存在指令重排序问题(这里可能是,同步块儿可以确保创建新DCL变量连续地完成,但s=sl这个赋值动作和同步块儿是平行的)。
也可以在方法名前使用volatile关键字禁止重排序。