1、单例模式
保证一个类仅有一个实例,并提供一个访问他的全局访问点。(俗称:构造方法的私有化)
如交易所的核心交易引擎类,控制着交易流程,如果可以创建多个的话,交易流程无法得到保障。
实例一:
public class Singleton { private static Singleton instance = null; // 构造方法私有化 private Singleton() { } public static Singleton getInstance() { if (null == Singleton.instance) { Singleton.instance = new Singleton(); } return Singleton.instance; } } 该类并不是线程安全的,如果置于多线程下,依然无法保证只产生一个实例
实例二:
public class Singleton { private static Singleton instance = null; // 构造方法私有化 private Singleton() { } public static synchronized Singleton getInstance() { if (null == Singleton.instance) { Singleton.instance = new Singleton(); } return Singleton.instance; } } // 我们可以通过在方法getInstance()添加synchronized来锁住对象,但是会导致性能下降,事实上 // 只有在第一次创建对象的时候需要锁,之后就不需要了,所以可以将创建该类实例的代码放入到同步块中 public static Singleton getInstance() { if (null == Singleton.instance) { synchronized (Singleton.instance) { if (null == Singleton.instance) { Singleton.instance = new Singleton(); } } } return Singleton.instance; }
实例三:
/** * 实例二也有存在问题的可能。看下面的情况:在Java指定中创建对象和赋值操作时分开进行的,也就是说 instance = new Singleton();语句是分两步执行的,同时JVM并不保证这两个操作的先后 * 顺序,也就是说可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去 初始化这个Singleton实例。 以A、B两个线程为例: * * 1):A、B线程同时进入了第一个if判断中; 2):A首先进入到synchronized块,此时instance == null,所以他执行instance = new Singleton(); * 3):JVM先画出一些分配给Singleton实例的空白内存,并赋值给instance成员( 注意:此时JVM没有开始初始化这个实例), 然后A离开了synchroized块。 * 4):B进入synchronized块,此时instance == 此时不是null,B线程直接返回结果。 5):此时B线程打算使用Singleton实例,却发现没有被初始化,于是错误发生。 * * * * 这里我们暂时总结一个相对完美的单列模式:<br> * 原理:单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。<br> * 这样当我们第一次调用getInstance()时,JVM能够帮我们保证instance制备创建一次,并会保证吧赋值给instance的内存<br> * 初始化完毕。同时该方法也只会在第一次调用的时候使用互斥机制,这样就能解决了低性能问题。 * */ public class Singleton { // 构造方法私有化 private Singleton() { } // 内部类来维护单例实例 private static class SingletonFactory { private static Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonFactory.instance; } }