天天看點

Java設計模式-單例模式:單例的六種實作單例模式的定義單例模式的實作單例模式的優缺點

單例模式的定義

確定某一個類隻有一個執行個體,而且自行執行個體化并向整個系統提供這個執行個體。

UML類圖

Java設計模式-單例模式:單例的六種實作單例模式的定義單例模式的實作單例模式的優缺點

單例類的構造函數是 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 的方式對方法加鎖,會影響效率。

雙重校驗鎖懶漢式

/**
 * 雙重校驗鎖懶漢式(線程安全,且多線程環境下可以保持高性能)
 *
 * @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之後版本使用。

單例模式的優缺點

優點

  • 單例模式在記憶體中隻有一個執行個體,減少了記憶體開支,尤其是頻繁的建立和銷毀執行個體。
  • 由于隻生成一個執行個體,是以減少了系統的性能開銷。
  • 避免對資源的多重占用,例如寫檔案操作。
  • 單例模式可以在系統設定全局的通路點,優化和共享資源通路。

缺點

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