1. 程式人生 > 實用技巧 >詳解單例模式多種實現方式及其特性(餓漢/懶漢/雙重檢測鎖/靜態內部類/列舉/註冊式)

詳解單例模式多種實現方式及其特性(餓漢/懶漢/雙重檢測鎖/靜態內部類/列舉/註冊式)

/**
 * 單例模式
    將建構函式私有化
    在類的內部建立例項
    提供獲取唯一例項的方法
 */
// 建立想要實現單例設計的Java類,如下:
public class SingletonModel {
    private SingletonModel(){
        System.out.println("model 被建立");
    }
    private SingletonModel(int i){

    }

餓漢

    private static final SingletonModel hungry = new SingletonModel();
    public static  SingletonModel getInstance() {
           return hungry;
    }

懶漢

    private static SingletonModel lazyBoy1 = null;
    public static  SingletonModel getInstance() {
        if(lazyBoy1==null){
            lazyBoy1 = new SingletonModel();
        }
        return  lazyBoy1;
    }

雙重檢測鎖

    private static volatile SingletonModel lazyBoyDoubleCheckLock = null;
    public static  SingletonModel getInstance() {
        if(lazyBoyDoubleCheckLock==null){//僅第一次建立才需要加鎖
            synchronized (SingletonModel.class){
                if(lazyBoyDoubleCheckLock==null)
                    lazyBoyDoubleCheckLock = new SingletonModel();//不是原子操作的話,需要加volatile禁止重排序
            }
        }
        return  lazyBoyDoubleCheckLock;
    }

靜態內部類

    private static class InnerClass{
            //private static  Integer oo = 1;
        private static SingletonModel obj = new SingletonModel();
    }
    public static  SingletonModel getInstance() {
        return  InnerClass.obj;
    }

    public static void main(String[] args) {
        SingletonModel sg = new SingletonModel(1);
        System.out.println("sg inited");
        SingletonModel.getInstance();
        SingletonModel.getInstance();
        int i = 1;

    }
}

註冊式-列舉單例

// 列舉式單例模式也是 Effective Java 書中推薦的一種單例模式實現寫法。JDK 列舉的語法特殊性質及繁殖也為列舉報價護航,讓列舉式單例模式成為一種比較優雅的實現。
public enum  EnumSingleton {
    INSTANCE;
    public EnumSingleton getInstance(){
        return INSTANCE;
    }
}

註冊式-容器式單例

// 看起來比較麻煩,適用於單例例項非常多的情況
public class ContainerSingleton {
    private ContainerSingleton(){}
    private static Map<String,Object> ioc = new ConcurrentHashMap<String,Object>();
    public static Object getBean(String className){
        synchronized (ioc){
            if(!ioc.containsKey(className)){
                Object obj = null;
                try{
                    obj = Class.forName(className).newInstance();
                    ioc.put(className, obj);
                }catch (Exception e){
                    e.printStackTrace();
                }
                return obj;
            } else {
              return ioc.get(className);
            }
        }
    }
}