單例模式幾種寫法


1.餓漢式

public class SingletonInstance {
    //私有構造方法
    private static SingletonInstance (){

    }
    //聲明成員變量
    private static SingletonInstance singletonInstance = new SingletonInstance();
    //對外提供接口獲取該實例
    public static SingletonInstance getSingletonInstance(){
        return singletonInstance ;
    }

}

2.懶漢式

public class SingletonInstance {
    //私有構造方法
    private SingletonInstance (){

    }
    //聲明成員變量
    private static SingletonInstance singletonInstance ;
    //對外提供接口獲取該實例
    public static SingletonInstance getSingletonInstance(){
        if(singletonInstance == null){
            singletonInstance = new SingletonInstance();
        }
        return singletonInstance ;
    }

}

 

餓漢式 懶漢式是經典的單例寫法,但是線程不安全,當然,為保證線程安全,可以對getSingletonInstance()函數加鎖,如下:

 public static synchronized SingletonInstance getSingletonInstance(){
        return singletonInstance = new SingletonInstance();
    }

但是這樣每次獲取單例都會判斷鎖,會很消耗資源,所以餓漢式和懶漢式不推薦使用,推薦使用以下方式

3.double check lock(dcl)

public class SingletonInstance {
    //私有構造方法
    private SingletonInstance (){

    }
    //聲明成員變量
    private static SingletonInstance singletonInstance ;
    //對外提供接口獲取該實例
    public static SingletonInstance getSingletonInstance(){
        if(singletonInstance == null){
            synchronized (SingletonInstance.class){
                //兩次判斷是否為null
                if(singletonInstance==null){
                    singletonInstance = new SingletonInstance();
                }
            }
        }
        return singletonInstance ;
    }

}

DCl 資源利用率高,執行效率也高,缺點是第一次加載的時候會比較慢,而且在高並發的時候,有可能會導致單例不成功(概率很小),推薦使用這種方式

4.靜態內部類

public class SingletonInstance {
    //私有構造方法
    private SingletonInstance (){

    }
    
    private static class Builder{
        //聲明成員變量
        private static SingletonInstance singletonInstance = new SingletonInstance();
    }
    //對外提供接口獲取該實例
    public static SingletonInstance getSingletonInstance(){
        return Builder.singletonInstance ;
    }

}

這種方法,實例只會被創建一次,而且只有在被引用的時候創建,線程安全也能保證,所以推薦使用這種方式

5.以上四種方法,不管哪種方法,在反序列化的時候,都不能保證單例。但是使用枚舉可以避免這個問題,枚舉默認就是線程安全的

public enum Singleton {  //enum枚舉類
    INSTANCE;  
}

但是枚舉在android中是不建議使用的,因為枚舉比constants消耗更大的內存,

6.單例管理類創建單例

public class SingletonManager { 
  private static Map<String, Object> objMap = new HashMap<String,Object>();//使用HashMap作為緩存容器
  private Singleton() { 
  }
  public static void registerService(String key, Objectinstance) {
    if (!objMap.containsKey(key) ) {
      objMap.put(key, instance) ;//第一次是存入Map
    }
  }
  public static ObjectgetService(String key) {
    return objMap.get(key) ;//返回與key相對應的對象
  }
}

7.反序列化杜絕生成新的實例,需要加入以下這個函數

private Object readResolve()  throws ObjectStreamException{
    return INSTANCE;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM