1. 程式人生 > >java單例五種實現模式梳理

java單例五種實現模式梳理

添加 多例 直接 枚舉類 一次 默認 實現 不必要 ade

java單例五種實現模式

餓漢式(線程安全,調用效率高,但是不能延時加載)
  • 一上來就把單例對象創建出來了,要用的時候直接返回即可,這種可以說是單例模式中最簡單的一種實現方式。但是問題也比較明顯。單例在還沒有使用到的時候,初始化就已經完成了。也就是說,如果程序從頭到位都沒用使用這個單例的話,單例的對象還是會創建。這就造成了不必要的資源浪費。所以不推薦這種實現方式。
public class ImageLoader{ 
     private static ImageLoader instance = new ImageLoader; 
     private ImageLoader(){} 
     public static ImageLoader getInstance(){  
          return instance;  
      } 
}
懶漢式(線程安全,調用效率不高,但是能延時加載)
  • 懶漢式(線程安全,調用效率不高,但是能延時加載)
public class SingletonDemo2 {
     
    //類初始化時,不初始化這個對象(延時加載,真正用的時候再創建)
    private static SingletonDemo2 instance;
     
    //構造器私有化
    private SingletonDemo2(){}
     
    //方法同步,調用效率低
    public static synchronized SingletonDemo2 getInstance(){
        if(instance==null){
            instance=new SingletonDemo2();
        }
        return instance;
    }
}
靜態內部類實現模式(線程安全,調用效率高,可以延時加載)
  • 可以看到使用這種方式我們沒有顯式的進行任何同步操作,那他是如何保證線程安全呢?和餓漢模式一樣,是靠JVM保證類的靜態成員只能被加載一次的特點,這樣就從JVM層面保證了只會有一個實例對象。那麽問題來了,這種方式和餓漢模式又有什麽區別呢?不也是立即加載麽?實則不然,加載一個類時,其內部類不會同時被加載。一個類被加載,當且僅當其某個靜態成員(靜態域、構造器、靜態方法等)被調用時發生。
  • 但是在遇到序列化對象時,默認的方式運行得到的結果就是多例的。這種情況不多做說明了,使用時請註意。
 public class SingletonDemo3 {
      
     private static class SingletonClassInstance{
         private static final SingletonDemo3 instance=new SingletonDemo3();
     }
      
     private SingletonDemo3(){}
      
     public static SingletonDemo3 getInstance(){
         return SingletonClassInstance.instance;
     }
      
 }
枚舉類(線程安全,調用效率高,不能延時加載,可以天然的防止反射和反序列化調用)
 public enum SingletonDemo4 {
      
     //枚舉元素本身就是單例
     INSTANCE;
      
     //添加自己需要的操作
     public void singletonOperation(){     
     }
 }
Double CheckLock實現單例:DCL也就是雙重鎖判斷機制(由於JVM底層模型原因,偶爾會出問題,不建議使用)

選用

  • 單例對象 占用資源少,不需要延時加載,枚舉 好於 餓漢
  • 單例對象 占用資源多,需要延時加載,靜態內部類 好於 懶漢式

    註意線程安全問題

java單例五種實現模式梳理