Java設計模式-單例模式:單例的六種實現

原文地址:xeblog.cn/articles/16git

單例模式的定義

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

UML類圖設計模式

單例類的構造函數是 private 內部私有的,確保外部不能經過 new 的方式建立新對象,內部自行實例化,並對外提供一個訪問該單一實例的靜態的方法 Instance()安全

單例模式的實現

普通餓漢式

/** * 普通餓漢式 * * @author anlingyi */
public class Singleton {
    /** * 類加載時進行實例化對象 */
    private static final Singleton SINGLETON = new Singleton();

    /** * 私有構造,防止外部new對象 */
    private Singleton() {

    }

    /** * 經過靜態方法獲取對象實例 * * @return */
    public static Singleton getInstance() {
        return SINGLETON;
    }

    public void say() {
        System.out.println("普通餓漢式:Hello World!");
    }
}
複製代碼

調用方式:多線程

Singleton singleton = Singleton.getInstance();
singleton.say();
複製代碼

優缺點

優勢: 類加載時就進行實例化,以後的操做效率會很高。
缺點: 因爲類加載時就進行實例化,若是後續不對此類進行任何操做,就會致使內存的浪費。函數

線程不安全的懶漢式

/** * 懶漢式(線程不安全) * * @author anlingyi */
public class SingletonTwo {

    private static SingletonTwo instance;

    /** * 私有構造,防止外部new對象 */
    private SingletonTwo() {

    }

    /** * 經過靜態方法獲取對象實例 * * @return */
    public static SingletonTwo getInstance() {
        if(instance == null) {
            instance = new SingletonTwo();
        }

        return instance;
    }

    public void say() {
        System.out.println("懶漢式(線程不安全):Hello World!");
    }
}
複製代碼

調用方式:性能

SingletonTwo singleton = SingletonTwo.getInstance();
singleton.say();
複製代碼

優缺點

優勢: 在第一次調用的時候才進行實例化。
缺點: 當多個線程同時進入到 if(instance == null) {...} 時,會建立多個對象。測試

同步鎖懶漢式

/** * 同步鎖懶漢式(線程安全,效率低) * * @author anlingyi */
public class SingletonThree {

    private static SingletonThree instance;

    /** * 私有構造,防止外部new對象 */
    private SingletonThree() {

    }

    /** * 經過靜態方法獲取對象實例 * * @return */
    public static synchronized SingletonThree getInstance() {
        if(instance == null) {
            instance = new SingletonThree();
        }

        return instance;
    }

    public void say() {
        System.out.println("同步鎖懶漢式(線程安全,效率低):Hello World!");
    }
}
複製代碼

調用方式:優化

SingletonThree singleton = SingletonThree.getInstance();
singleton.say();
複製代碼

優缺點

優勢: 在第一次調用的時候才進行實例化,且線程安全。
缺點: 使用 synchronized 的方式對方法加鎖,會影響效率。spa

雙重校驗鎖懶漢式

/** * 雙重校驗鎖懶漢式(線程安全,且多線程環境下能夠保持高性能) * * @author anlingyi */
public class SingletonFour {

    /** * volatile是爲了防止指令重排序 */
    private static volatile SingletonFour instance;

    /** * 私有構造,防止外部new對象 */
    private SingletonFour() {

    }

    /** * 經過靜態方法獲取對象實例 * * @return */
    public static SingletonFour getInstance() {
        if(instance == null) {
            synchronized (SingletonFour.class) {
                if(instance == null) {
                    instance = new SingletonFour();
                }
            }
        }

        return instance;
    }

    public void say() {
        System.out.println("雙重校驗鎖懶漢式(線程安全,且多線程環境下能夠保持高性能):Hello World!");
    }
}
複製代碼

調用方式:

SingletonFour singleton = SingletonFour.getInstance();
singleton.say();
複製代碼

優缺點

優勢: 在第一次調用的時候才進行實例化,且線程安全,效率較高。
缺點: 實現複雜,且 volatile 須要在JDK1.5以後的版本才能確保安全。

靜態內部類懶漢式

/** * 靜態內部類懶漢式 * * @author anlingyi */
public class SingletonFive {

    /** * 私有構造,防止外部new對象 */
    private SingletonFive() {

    }

    /** * 經過靜態方法獲取對象實例 * * @return */
    public static SingletonFive getInstance() {
        return Singleton.SINGLETON;
    }

    public void say() {
        System.out.println("靜態內部類懶漢式:Hello World!");
    }

    /** * 靜態內部類實例化對象 */
    private static class Singleton {
        /** * 類加載時進行實例化對象 */
        private static final SingletonFive SINGLETON = new SingletonFive();
    }
}

複製代碼

調用方式:

SingletonFive singleton = SingletonFive.getInstance();
singleton.say();
複製代碼

優缺點

優勢: 只有在調用 getInstance() 方法的時候,靜態內部類纔會被加載,從而對主類(咱們須要的類)進行實例化,即線程安全,又效率高。
缺點: 多建立一個類。

枚舉類餓漢式(防止反序列化)

/** * 枚舉類餓漢式(防止反序列化) * * @author anlingyi */
public enum  SingletonSix {
    INSTANCE;

    public void say() {
        System.out.println("枚舉類餓漢式(防止反序列化):Hello World!");
    }
}
複製代碼

調用方式:

SingletonSix singleton = SingletonSix.INSTANCE;
singleton.say();
複製代碼

優缺點

優勢: 實現簡單,防止反序列化生成多個實例,且線程安全。
缺點: Enum 需在JDK1.5以後版本使用。

單例模式的優缺點

優勢

  • 單例模式在內存中只有一個實例,減小了內存開支,尤爲是頻繁的建立和銷燬實例。
  • 因爲只生成一個實例,因此減小了系統的性能開銷。
  • 避免對資源的多重佔用,例如寫文件操做。
  • 單例模式能夠在系統設置全局的訪問點,優化和共享資源訪問。

缺點

  • 單例模式不易擴展,若要擴展,除了修改代碼外別無他法。
  • 單例模式對測試不利。
  • 單例模式與單一職責原則有衝突,一個類應該只實現一個邏輯,而不用關心它是不是單例的。

資源

參考

  • 《設計模式之禪》
相關文章
相關標籤/搜索