2018-1-12 by Atlasjava
單例模式確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例單例模式。單例模式只應在有真正的「單一實例」的需求時纔可以使用。安全
(1)若是有1個以上的對象實例時,因爲對象實例彼此之間的影響,可能會發展成出乎意料的BUG。
(2)須要控制類的對象實例的數量,以下降資源的使用時。多線程
- 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() {} // 忽略其餘 }