13 分鐘閱讀

單例模式

當你需樣以下幾個功能

  1. log紀錄
  2. 驅動程式
  3. 計分板
  4. 物件池
  5. 執行續池
  6. 提示視窗

這幾個只需要一個物件就可以處理的時候
不小心產生了兩個,不只會導致非預想的結果
還會有多餘的資源浪費

全域變數 VS 單例模式

你可以在程式定義一些全域變數
可以做到與單例模式一樣的效果

但有一些差別

  1. 控制物件的初始化時間,例如當你用不到這物件時,單例模式可以節省下記憶體
  2. 全域變數會因為執行順序影響到初始化

單例模式的範例

  1. 建構式是私有的
  2. 提供一個全域接觸點
public class Singleton{
  private static Singleton Instance;

  private Singleton(){}

  public static Singleton getInstance(){
    if(Instance == null)
      Instance = new Singleton();

    return Instance;
  }
}

單例模式VS多執行序

單例模式在多執序下

可能會造成非預期的執行順序

0 1 2 3 4 5 6 7 8
thread1 1 - 2 - 4 5 - -
thread2 - 1 - 2 - - 4 5

本來預想是只能初始化一個實例,但如果初始化兩次
就會造成許多意外錯誤

優化執行序的問題

1.lazy與eager 建立方式

lazy是當應用程式有需求時,才會去建立物件

public static Singleton getInstance(){
  if(Instance == null)
    Instance = new Singleton();

  return Instance;
}

eager是直接在應用程式上面,實例化單例模式
當你的運行成本還在可控範圍內可以使用

private static Singleton Instance = new Singleton();

2.使用同步

可以使多個執行序比需等待這個區塊的程式碼
不過前提是這個區塊的效能就會低下,每個執行序必須等待上一個執行完

C#範例:
使用lock,一次只有一個線程可以進入此區塊

private static readonly object padlock = new object();
public static Singleton Instance
{
  get
  {
    lock (padlock)
    {
      if (instance == null)
      {
        instance = new Singleton();
      }
      return instance;
    }
  }
}

java範例:
加入synchronized關鍵字

public static synchronized Singleton getInstance(){
  if(Instance == null)
    Instance = new Singleton();

  return Instance;
}

3.雙重檢查鎖

使用雙重檢查鎖,可以在第一次還未初始化時才同步
因此可以增加執行效率

C#範例:
在第一層判斷實例化的地方加入lock
如此可以在第一次還未初始化時才同步

private static readonly object padlock = new object();
public static Singleton Instance
{
  get
  {
    if (instance == null)
    {
      lock (padlock)
      {
        if (instance == null)
        {
          instance = new Singleton();
        }
      }
    }
    return instance;
  }
}

java範例:
加入volatile關鍵字,可以對使用此關鍵字的變數使用synchronized

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

參考資料:
C# 單例模式