【設計模式】單例模式

前幾天面試一個校招的小朋友,讓他寫單例模式,沒寫出來,所以這裏把兩年前我的學習筆記發一下。這應該是所有設計模式中最簡單的設計模式了,從它講起。

用途

用來創建獨一無二對象。確保只有一個實例,並且提供一個全局訪問點(getSingleton)。

v0.0.1-簡單實現

/**
 * Created by Acceml on 2016/5/28.
 * Email: [email protected]
 */
public class Singleton {
    private static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSingleton() {
        if(singleton == null) {//risk
            return new Singleton();
        }
        return singleton;
    }
}

要注意的點是:

  • 單例模式沒有public的construct
  • 有一個靜態的對象,每次getSingleton()的時候獲得的是同一個

這樣寫的問題是: 多線程的時候回出問題,比如我們有兩個線程thread0,thread1去同時調用getSingleton()這個方法,就會在if(singleton == null)出現問題。thread0,thread1都認爲沒有該判斷爲true,就會去創建兩個對象,沒有多線程的時候,這樣使用沒有問題。

V0.0.2-雙檢查實現

/**
 * Created by Acceml on 2016/5/28.
 * Email: [email protected]
 */
public class Singleton {
    private volatile static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSingleton() {
        if(singleton == null) {//判斷1
            synchronized (Singleton.class) {
                if(singleton == null) {//判斷2
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

變化有:

  • 加了volatile關鍵字
  • 加了雙重鎖 加volatile很容易理解,因爲加上該關鍵字,那麼變量就對不同線程可見。在方法getSingleton()中,第一個判斷不存在,就進入同步塊,進入同步塊之後再判斷一次,還是爲null才創建實例。但是爲什麼這麼做呢?假如thread0執行到判斷1,它進入同步區之後,thread2就進不來了,從而保證只有一個線程執行到判斷2。

v0.0.3-eager實現

上面兩種方法都是我們需要的時候去做判斷,然後實例化,如果創建對象負擔不重的話,可以考慮在靜態初始化的時候創建對象。

/**
 * Created by Acceml on 2016/5/28.
 * Email: [email protected]
 */
public class Singleton {
    private volatile static Singleton singleton = new Singleton();

    private Singleton() {
    }

    public static Singleton getSingleton() {
        return singleton;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章