Java單例類(餓漢式,懶漢式,雙重檢查鎖,靜態私有內部類,枚舉)-劍指office面試題2


定義:一個類有且僅有一個實例,並且自行實例化向整個系統提供。
作用:解決一個全局使用的類頻繁地創建與銷燬的問題。
優點:減少內存開銷,避免對資源的多重佔用。
缺點:沒有接口,不能繼承。
實現方式:餓漢式,懶漢式,雙重檢查鎖,靜態私有內部類,枚舉

餓漢式

/* 餓漢式單例類*/
public class Singleton {
    private Singleton(){
    }

    private static Singleton instance = new Singleton();

    public static Singleton getInstance(){
        return instance;
    }
}

缺點:不支持併發,只能在單線程中使用,加載時就已經創建好了實例,不管用不用。

懶漢式

懶漢式(不支持併發)

/* 懶漢式-- 不支持併發 */
public class Singleton2 {
    private Singleton2(){
    }
    private static Singleton2 instance = null;
    private static Singleton2 getInstance(){
        if (instance == null){
            instance = new Singleton2();
        }
        return instance;
    }
}

缺點:不支持併發,只能在單線程中使用。
優點:只有在調用獲取實例的方法時才創建實例。

懶漢式(支持併發)

/*餓漢式--支持併發*/
public class Singleton3 {
    private Singleton3(){
    }
    private static Singleton3 instance = null;
    private synchronized static Singleton3 getInstance(){
        if (instance == null){
            instance = new Singleton3();
        }
        return instance;
    }
}

缺點:synchronized鎖住了整個方法,當有多個線程需要訪問方法時,不管實例有沒有創建,都需要排隊等待才能拿到實例,效率低。

兩個懶漢式的區別:加不加 sybchronized。

雙重檢查鎖、volatile(常用)

public class Singleton4 {
    private Singleton4(){
    }

    private volatile static  Singleton4 instance = null;
    private static  Singleton4 getInstance(){
        if (instance == null){ //1
            synchronized (Singleton4.class){
                if (instance == null){ //2
                    instance = new Singleton4();
                }
            }
        }
        return instance;
    }
}

volatile 關鍵字保證了內存可見性,所有線程都會去主存中取數據而不是在線程的緩存中取,保證了數據的更新能實時地對任何線程可見。
假如有兩個線程同時到達了1,它們都去創建實例,這時候如果沒有第二次判斷,就會多次創建實例了。二次判斷保證了多線程下只創建一個實例。

靜態內部私有類(常用)

public class Singleton5 {
    private Singleton5(){

    }

    private static class Singleton5Holder{
        private static Singleton5 instance = new Singleton5();
    }

    public static Singleton5 getInstance(){
        return Singleton5Holder.instance;
    }
}

靜態內部類不會隨着外部類的加載而加載 ,只有靜態內部類的靜態成員被調用時纔會進行加載(實例化)。同時,虛擬機會保證一個類的構造器方法在多線程環境中被正確地加載,同步,如果多個線程同時去初始化一個類,那麼只有一個線程去執行這個類的。所以這種方法支持多併發效率高

枚舉

public enum Singleton6 {
    INSTANCE;
}

外部調用由原來的Singleton.getInstance變成了Singleton.INSTANCE了。

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