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() {} // 忽略其余 }