單例模式

定義

單例模式確保某個類只有一個實例,並且自行實例化並向整個系統提供這個實例。java

特色

  • 單例類只能有一個實例
  • 單例類必須本身建立本身的惟一實例
  • 單例類必須給全部其餘對象提供這一實例

單例模式的三種寫法

餓漢式

public class Singleton{
       
       private static Singleton instance=new Singleton();
       //私有構造器,防止被屢次new建立
       private Singleton(){}
       
       public static Singleton getInstance(){
           return instance;
        }      
 
  }
  • 優勢:這種寫法比較簡單,就是在類加載的時候就完成實例化。避免了線程同步問題。
  • 缺點:在類加載的時候就完成實例化,沒有達到Lazy Loading的效果。若是從始至終都沒使用過這個實例,則會形成內存的浪費。

靜態內部類

public class Singleton{

    //私有構造器,防止被屢次new建立
    private Singleton(){}
    
    //把instance的實例放到靜態類內部
    private static class SingletonInstance{
        private static final Singleton instance=new Singleton();
    }
    
    //調用getInstance方法時加載靜態內部類
    public static Singleton getInstance(){
        return SingletonInstance.instance;
    }
)
  • 靜態內部類方式在Singleton類被裝載時並不會當即實例化,而是在須要實例化時,調用getInstance方法,纔會裝載SingletonInstance類。

雙重檢查(推薦)

public class Singleton{
    
    //volatile關鍵字確保多個線程正確地處理instance變量
    private volatile static Singleton instance;
    
    //私有構造器,防止被屢次new建立
    private Singleton(){}
    
    piblic static Singleton getInstance(){
        //第一次檢查
        if(instance==null){
            synchronized(Singleton.class){
                //第二次檢查
                if(instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

爲何instance須要用volatile修飾?
由於new Singleton()可能會發生重排序,具體能夠分爲三個步驟:
一、爲對象分配內存
二、初始化對象
三、讓instance指向內存地址
這種狀況下可能會發生重排序,也就是變成1——>3——>2(單線程下並無改變結果,因此這是容許的,可是多線程下可能會返回未初始化的instance),所以須要volatile禁止重排序多線程

相關文章
相關標籤/搜索