【Java】設計模式--單例模式

單例模式

單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。

這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。

1、單例類只能有一個實例。
2、單例類必須自己創建自己的唯一實例。
3、單例類必須給所有其他對象提供這一實例。

單例模式結構圖

                                               

單例模式實現方式

1.餓漢式

public class Singleton { 
 
     private static Singleton instance = new Singleton(); 
      
     private Singleton (){}

     public static Singleton getInstance() {  
         return instance;  
     }  
 } 
這種方式在類加載時就完成了初始化,所以類加載較慢,但獲取對象的速度快。 這種方式基於類加載機制避免了多線程的同步問題,但是也不能確定有其他的方式(或者其他的靜態方法)導致類裝載,這時候初始化instance顯然沒有達到懶加載的效果。

2.懶漢式

2.1懶漢式(線程不安全)

public class Singleton {  
      private static Singleton instance; 
       
      private Singleton (){}  
       
      public static Singleton getInstance() {  
          if (instance == null) {  
          instance = new Singleton();  
          }  
          return instance;  
      }  
 }  

懶漢模式申明瞭一個靜態對象,在用戶第一次調用時初始化,雖然節約了資源,但第一次加載時需要實例化,反映稍慢一些,而且在多線程不能正常工作。

2.2懶漢式(線程安全)

public class Singleton {  
      private static Singleton instance;  
      
      private Singleton (){}
      
      public static synchronized Singleton getInstance() {  
          if (instance == null) {  
              instance = new Singleton();  
          }  
          return instance;  
      }  
 } 

這種寫法能夠在多線程中很好的工作,但是每次調用getInstance方法時都需要進行同步,造成不必要的同步開銷,而且大部分時候我們是用不到同步的,所以不建議用這種模式。

3.雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)

public class Singleton {  
    private volatile static Singleton singleton;
      
    private Singleton (){}  
    
    public static Singleton getSingleton() {  
        if (singleton == null) {  
            synchronized (Singleton.class) {  
                if (singleton == null) {  
                    singleton = new Singleton();  
                }  
            }  
        }  
        return singleton;  
    }  
}

這種方式採用雙鎖機制,安全且在多線程情況下能保持高性能。getInstance() 的性能對應用程序很關鍵。

4.登記式/靜態內部類

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){} 
     
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}   

這種方式能達到雙檢鎖方式一樣的功效,但實現更簡單。對靜態域使用延遲初始化,應使用這種方式而不是雙檢鎖方式。這種方式只適用於靜態域的情況,雙檢鎖方式可在實例域需要延遲初始化時使用。

5.枚舉

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {}  
} 

默認枚舉實例的創建是線程安全的,並且在任何情況下都是單例。

上述講的幾種單例模式實現中,有一種情況下他們會重新創建對象,那就是反序列化,將一個單例實例對象寫到磁盤再讀回來,從而獲得了一個實例。

反序列化操作提供了readResolve方法,這個方法可以讓開發人員控制對象的反序列化。

在上述的幾個方法示例中如果要杜絕單例對象被反序列化是重新生成對象,就必須加入如下方法:

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

 

https://www.jianshu.com/p/056feb1f3d1a

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