synchronized能不能保證有序性??

肯定能啊。
但是:
比如單例模式裏面的雙檢鎖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中使用內存屏障一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章