肯定能啊。
但是:
比如單例模式裏面的雙檢鎖dcl,爲什麼還要加volatile禁止指令重排序呢??
class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
那我們首先要明白:
爲啥synchronized無法禁止指令重排,但可以保證有序性?
加了鎖之後,只能有一個線程獲得到了鎖,獲得不到鎖的線程就要阻塞。所以同一時間只有一個線程執行,相當於單線程,而單線程的指令重排是沒有問題的。
上述代碼的字節碼:
- 17:new 一個對象
- 20:複製一份對象引用//地址
- 21:利用一個對象引用,調用構造方法。//根據引用地址調用
- 24:表示利用一個對象引用,賦值給static instance
jvm(java virtual machine)可能會先執行24,在執行21。即先賦值,再引用。加了synchronized相當於是單線程。沒有問題的。但比如線程1獲得到了鎖,先執行24,在執行21。此時線程2也執行判斷實例不爲空,直接執行到了37步,得到了靜態變量引用,然後return,之後開始使用這個對象了。與此同時線程1的 21(初始化)還沒有完成。
所以問題就是線程2使用的對象可能是未完全初始化的對象。
最好的解決有序性問題的辦法,就是禁止處理器優化和指令重排,就像volatile中使用內存屏障一樣。