1. 程式人生 > >23種設計模式之單例模式

23種設計模式之單例模式

所有 存在 ins 結果 我們 程序 排序 volatil 計算機

單例模式(保證java程序中某個類只有一個實例存在)

單例模式有以下的特點:

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

在計算機系統中,線程池,緩存,日誌對象,打印機,對話框常常被設計成單例對象。選擇單例模式就是為了避免不一致狀態。

一、懶漢式

public class Singleton{

private Singleton singleton = null;

private Singleton(){}
private static Singleton getSingleton(){ if(singleton = null
){ singleton = new Singleton(); } return singleton; } }

Singleton通過將構造器私有化,避免了在類外實例化,Singleton的實例只能通過getSingleton()方法訪問(不考慮反射)。

以上的懶漢式的代碼是沒有考慮線程安全的,可以通過以下三種方式將代碼進行改造

1.在getSingleton()方法上添加同步(同步是需要開銷的,正常執行的代碼我們不需要同步,只需要在對象初始化的時候同步)

private static synchronized Singleton getSingleton(){
   if
(singleton = null){ singleton = new Singleton(); }
}

2.雙重檢查鎖定(double-checked locking)

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

雙重檢查鎖定存在一個問題,這個問題是由指令重排序引起的。指令重排序是為了優化指令,提高程序運行效率,包括編譯器重排序和運行時重排序,指令重排序可以在不影響單線程程序執行結果的前提下進行。例如:instance = new Singleton();可以分解為以下偽代碼:

memory = allocate();//1.分配對象的內存空間
ctorInstance(memory);//2.初始化對象
instance = memory;//3.instance指向剛才分配的內存空間

經過指令重排序後:

memory = allocate();//1.分配對象的內存空間
instance = memory;//3.instance指向剛才分配的內存空間
ctorInstance(memory);//2.初始化對象

將第2步和第三部調換順序後,對於單線程的執行結果是沒有影響的,但是對於多線程就不一樣了。線程A執行了instance = memory(這對另外一個線程B是可見的),線程B這個時候通過 if(instance == null)判斷instance不為空,隨機返回,這個時候拿到的是未被完全初始化的實例,在使用的時候會有風險,這就是雙重檢查鎖定存在的問題。

在jdk1.5之後可以使用volatile禁止指令重排序:

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

3.靜態內部類(占位類)

public class Singleton {  
    private static class InstanceHolder {  
        public static Singleton instance = new Singleton();  
    }  
  
    private Singleton() {  
    }  
  
    public static Singleton getInstance() {  
        return InstanceHolder.instance;  
    }  
}  

二、餓漢式

public class Singleton{
    
  private  Singleton singleton = new Singleton();
  
  private Singleton(){}

  private Singleton getInstance(){

      return singleton;

   }      
}

23種設計模式之單例模式