設計模式-單例(Singleton)

2018-1-12 by Atlasjava


  • 設計思想

單例模式確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例單例模式。單例模式只應在有真正的「單一實例」的需求時纔可以使用。安全

  • 應用場景

(1)若是有1個以上的對象實例時,因爲對象實例彼此之間的影響,可能會發展成出乎意料的BUG。
(2)須要控制類的對象實例的數量,以下降資源的使用時。多線程

  • UML 類圖

Singleton UML

  • UML中加「-」表示私有的(private);
  • UML中加「+」表示公有的(public);
  • UML中加「_」表示靜態的(static)。

Singleton模式基本構成:併發

  • 靜態的私有的類成員變量singleton,私有的表示只有成員所生存的對象能夠訪問,靜態的表示類加載準備階段分配初始值、解析階段字符引用轉化爲直接引用;
  • 私有的類構造方法Singleton,私有的構造方法表示禁止非Singleton類調用實例構造器建立對象實例;
  • 靜態的公有的類方法getInstance,靜態的類方法表示類加載解析階段就從字符引用轉化爲直接引用,即內存中方法的實際地址,能夠經過類.方法直接調用。
  • 標準示例
public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton() {
        System.out.println("已產生對象實例。");
    }
    public static Singleton getInstance() {
        return singleton;
    }
}
public static void main(String[] args) {
    Singleton s1 = Singleton.getInstance();
    Singleton s2 = Singleton.getInstance();
    System.out.println(s1 == s2);
}
  • 拓展現例

延遲對象實例化app

  • 優勢:
    類加載時不進行目標對象的實例化操做,提升了類加載的速度,實際訪問須要時才進行目標對象的實例化。
  • 缺點:
    相比類加載時就進行目標對象實例化,延遲實例化可能致使多線程併發時產生線程安全問題,須要同步訪問入口方法以達到線程安全的目的,理論上下降了多線程併發訪問的效率。
public class Singleton {
    private static Singleton singleton;
    private Singleton() {
            System.out.println("已產生對象實例。");
    }
    public static synchronized Singleton getInstance() {
            if(singleton == null){
                singleton = new Singleton();
            }
            return singleton;
    }
}
public static void main(String[] args) {
    Singleton s1 = Singleton.getInstance();
    Singleton s2 = Singleton.getInstance();
    System.out.println(s1 == s2);
}

那麼問題來了,有沒有一種一箭雙鵰的方式呢,答案是有的。
靜態內部類實例化ide

  • 優勢:
    (1)外部類加載時無須進行目標對象的實例化操做,提升了類加載的速度,實際訪問須要時加載內部類並進行目標對象的實例化。
    (2)靜態內部類只會進行一次內部類的類變量的初始化,不會產生線程安全問題,無須同步,不會下降多線程併發訪問效率。
public class Singleton {
    private Singleton() {
        System.out.println("已產生對象實例。");
    }
    private static class SingletonHolder {
        private static Singleton singleton = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonHolder.singleton;
    }
}
  • 案例鑑賞

java.lang.Runtime#getRuntime()this

public class Runtime {
    private static Runtime currentRuntime = new Runtime();
    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }
    /** Don't let anyone else instantiate this class */
    private Runtime() {}
    // 忽略其餘
}
相關文章
相關標籤/搜索