Java單例模式之四種實現

單例模式一:飢餓模式

/**
 * 飢餓模式
 *
 * 不存在併發問題
 * @author [email protected]
 * @date 2020/3/6 0006 下午 9:12
 */
public class EagerSingleton {
    private static final EagerSingleton INSTANCE = new EagerSingleton();
    private EagerSingleton(){
        System.out.printf("%s: construct called....%n",getClass().getSimpleName());
    }
    public static EagerSingleton getInstance(){
        return INSTANCE;
    }

    public void sing(){
        System.out.printf("%s: Sing....%n",getClass().getSimpleName());
    }
}

單例模式二:DLC模式

即懶加載模式中的double lock check模式

/**
 * double lock check模式
 * @author [email protected]
 * @date 2020/3/6 0006 下午 9:13
 */
public class DoubleLockSingleton {

    //必須使用volatile 是因爲cpu有可能指令re-order,
    //此關鍵字會插入內存屏障,阻止cpu re-order
    private volatile static DoubleLockSingleton INSTANCE = null;
    private DoubleLockSingleton(){
        System.out.printf("%s: construct called....%n",getClass().getSimpleName());
    }

    public static DoubleLockSingleton getInstance(){

        //double check null
        if(INSTANCE == null){
            synchronized (DoubleLockSingleton.class){
                //must check again
                //because maybe another thread initialize it already
                if(INSTANCE == null){
                    INSTANCE = new DoubleLockSingleton();
                }
            }
        }
        return INSTANCE;

    }

    public void sing(){
        System.out.printf("%s: Sing....%n",getClass().getSimpleName());
    }

}

單例模式三:靜態內部類模式

優點:不需要double lock check

/**
 * When the singleton class is loaded,
 * inner class is not loaded and hence doesn’t create object when loading the class.
 * Inner class is created only when getInstance() method is called.
 * So it may seem like eager initialization but it is lazy initialization.
 * This is the most widely used approach as it doesn’t use synchronization.
 * @author [email protected]
 * @date 2020/3/6 0006 下午 9:16
 */
public class InnerClassSingleton {

    private InnerClassSingleton(){
        System.out.printf("%s: construct called....%n",getClass().getSimpleName());
    }


    private static class Holder{
        static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
    }

    public static InnerClassSingleton getInstance(){
        return Holder.INSTANCE;
    }

    public void sing(){
        System.out.printf("%s: Sing....%n",getClass().getSimpleName());
    }


}

單例模式四:枚舉模式

/**
 *
 * 這一種是最好的
 * 比InnerClassSingleton還好一點,因爲不用再定義一些不必須的屬性和內部類
 *
 * @author [email protected]
 * @date 2020/3/6 0006 下午 9:30
 */
public enum EnumSingleton {
    INSTANCE;

    private EnumSingleton(){
        System.out.printf("%s: construct called....%n",getClass().getSimpleName());
    }

    //etc
    private int propertyA;

    //etc....
    public void sing(){
        System.out.printf("%s: Sing....%n",getClass().getSimpleName());
    }

}

 

優劣比較

 

以前四種寫法均不存在併發問題,枚舉與飢餓模式寫法最簡便,個人比較推薦枚舉模式。

測試類

/**
 * test for singleton
 *
 * java -verbose:class SingletonBoot
 *
 * @author [email protected]
 * @date 2020/3/11 0011 上午 11:22
 */
public class SingletonBoot {
    public static void main(String[] args) {
        System.out.printf("%nBEGIN%n%n");

        EagerSingleton.getInstance().sing();
        DoubleLockSingleton.getInstance().sing();
        InnerClassSingleton.getInstance().sing();
        EnumSingleton.INSTANCE.sing();

        System.out.printf("%nEND%n%n");

    }
}

執行結果

BEGIN

[Loaded com.david.learning.concurrent.singleton.EagerSingleton]
[Loaded java.util.Formattable from rt.jar]
EagerSingleton: construct called....
EagerSingleton: Sing....
[Loaded com.david.learning.concurrent.singleton.DoubleLockSingleton]
DoubleLockSingleton: construct called....
DoubleLockSingleton: Sing....
[Loaded com.david.learning.concurrent.singleton.InnerClassSingleton]
[Loaded com.david.learning.concurrent.singleton.InnerClassSingleton$Holder]
InnerClassSingleton: construct called....
InnerClassSingleton: Sing....
[Loaded com.david.learning.concurrent.singleton.EnumSingleton]
EnumSingleton: construct called....
EnumSingleton: Sing....

END

 

澄清

飢餓模式寫法與DLC模式相比較並不比DLC耗資源,雖然它是飢餓模式,但其也是在使用這個類的地方纔會加載(引用成員或使用方法時初始化)它(變相懶加載)。

 

如有謬誤,請各位網友不吝指教。

 

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