计模式之单件模式(单例模式)
单件模式是最简单的设计模式啦!(窝感觉~~)
有一些对象我们只需要一个,例如:线程池(threadpool),缓存(cache),充当打印机,显卡等设备的驱动程序的对象。
这些类对象只能有一个实例,多了会出现一些问题。
全局变量缺点:必须在一开始就创建对象,浪费资源。
只创建一个对象的方法:首先将构造函数私有,这样这个类就不会随意的创建了。然后为类创建一个产生实例变量的方法。
public class MyClass { private MyClass() {} public static MyClass getIntance() { return new MyClass(); } }
单件模式的实现:
public class Singleton { private static Singleton uniqueSingleton; private Singleton() { } public static Singleton getInstance() { if (uniqueSingleton == null) { uniqueSingleton = new Singleton(); } return uniqueSingleton; } }
如果不需要这个实例,它就永远不会被产生,这就是“延迟实例化”(lazy-instantiaze)
单件模式:确保一个类只有一个实例,并提供一个全局访问点。
但是在多线程情况下,会产生一些问题,如下图情况:
呀~~产生了两个对象!
于是在多线程的时候
需要把getInstance()函数变成同步方法啦
public static synchronized Singleton getInstance() { if (uniqueSingleton == null) { uniqueSingleton = new Singleton(); } return uniqueSingleton; }
但是……同步会降低性能……
1.如果getInstance()方法的性能对应用程序不是很关键,就这样就可以了。
2.如果程序总是创建并使用单件实例,或者在创建或运行时方面的负担不太繁重,可以一开始就创建实例。
public class Singleton { private static Singleton uniqueSingleton = new Singleton(); private Singleton() { } public static Singleton getInstance() { return uniqueSingleton; } }
3.用双重加锁,在getInstance()中减少使用同步
public class Singleton { private volatile static Singleton uniqueSingleton; // volatile关键字确保 当uniqueSingleton被初始化后 // 多个线程正确的处理uniqueSingleton变量 private Singleton() { } public static Singleton getInstance() { if (uniqueSingleton == null) { // 检查实例 如果不存在就进入同步区 synchronized (Singleton.class) { if (uniqueSingleton == null) { // 进入区块后 在检查一次 如果仍然是null 才创建实例 uniqueSingleton = new Singleton(); // 注意:只有第一次才彻底执行这里的代码 } } } return uniqueSingleton; } }
4. 通过枚举实现单例模式
通过内部静态enum的方法来实现,因为JVM会保证enum不能被反射并且构造器方法只执行一次。
public class EnumSingleton { private EnumSingleton() {} public static EnumSingleton getInstance(){ return Singleton.INSTANCE.getInstance(); } private static enum Singleton{ INSTANCE; private EnumSingleton singleton; //JVM会保证此方法绝对只调用一次 private Singleton(){ singleton = new EnumSingleton(); } public EnumSingleton getInstance() { return singleton; } } }