1. 程式人生 > >設計模式1--單例模式

設計模式1--單例模式

單例模式,利用工廠類只生產一個例項或者有限個例項,比如一個系統中只有一個主機板,一個顯示卡,但是有些系統中也可以存在多個,雙顯示卡,雙顯示器等等。

這些在Singleton Module中都是可以定義的。當然我們也可以使用全域性的變數或者靜態類或者物件去做,但是單例模式的存在是有其優點的。

    public class SingletonFactory
    {
        public static SingletonFactory uniqueInstance = null;

        private SingletonFactory()
        {

        }

        public static SingletonFactory getInstance()
        {
            if (uniqueInstance == null)
            {
                uniqueInstance = new SingletonFactory();
            }
            return uniqueInstance;
        }
    }
單例模式的設計範例:

1. 有一個靜態的單例模式型別的例項,初始為null

public static SingletonFactory uniqueInstance = null;

2. 注意其建構函式應該為私有的,如果為公有則在外面就可以通過new來建立物件了,否則只能在類的內部呼叫new SingletonFactory()來建立物件,而這才是我們想要的。

3. 在getInstance函式中做一個判斷,就可以讓這個類的例項唯一了。

---------------------------------------------------------------------------------------------

但是這樣的做法在多執行緒中會有問題,因為程式是按時間片來執行,如果執行緒A正在執行

if (uniqueInstance == null)
因為是空,所以執行
uniqueInstance = new SingletonFactory();
但是還沒有執行將要執行之時,時間片現在跳轉到執行緒B來執行
if (uniqueInstance == null)
同樣會執行
 uniqueInstance = new SingletonFactory();
結果就是,因為多執行緒的原因使其存在了2個例項。。。這並不是我們想要看到的。
那麼解決這個問題的辦法有多種,各有優缺點。

1. 鎖住那個uniqueInstance,比較消耗資源。

 public static SingletonFactory getInstance()
        {
            lock(uniqueInstance)
            {
                if (uniqueInstance == null)
                {
                    uniqueInstance = new SingletonFactory();
                }
            }
            
            return uniqueInstance;
        }
2. 直接建立一個,但是有可能程式從頭到尾都沒用到過。
public static SingletonFactory uniqueInstance = new SingletonFactory();
3. 雙重檢查加鎖法,這個是比較推薦的

首先要

public static volatile SingletonFactory uniqueInstance = null;
或許我需要把static和volatile的區別開一個微博說一說,不過雖然static是靜態的,雖然在全域性只有一個例項,但是對於多執行緒來說有一個問題,這個例項雖然在A執行緒中被賦值,但是B執行緒在使用它的時候並不能完全確認是A執行緒賦值之前還是A執行緒賦值之後。於是乎,我們這裡用到了volatile,這個關鍵字的好處是對這個關鍵字修飾的變數賦值會使所有使用到他的地方的值都發生改變。

其次

   public static SingletonFactory getInstance()
        {
            if (uniqueInstance == null) //這裡先判斷
            {
                lock (uniqueInstance)  //然後再鎖
                {
                    if (uniqueInstance == null) //鎖完再判斷
                    {
                        uniqueInstance = new SingletonFactory();
                    }
                }
            }
            return uniqueInstance;
        }
這樣做的好處是,因為我們知道lock是比較消耗資源的,以上的雙重檢查加鎖的話,可以保證lock的操作只執行了一次。

因此我們比較推崇這種寫法。