单例模式
模式定义
单例模式确保一个类只有一个实例,并提供一个全局访问点。单例模式的本质是控制实例的数目,因此也就有人引申出多例模式(Multiton)。
模式结构说明
软件系统中的某些对象要求只能有一个,例如线程池、缓存、对话框、设备驱动程序对象,如果出现多个实例,可能导致程序行为异常或者过度的资源消耗,此时就有必要引入单例模式。
单例模式的优点:
- 可以控制客户如何、何时访问单例
- 避免全局变量造成的名字空间污染
应用举例
Java中的单例模式
需要注意的是,在Java中,单例限定于单个ClassLoader之内。
在单线程环境下的单例模式标准代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Singleton{ //私有化构造器,禁止外部实例化 private Singleton(){} private static Singleton instance; //获取单例 public static Singleton getInstance(){ if (instance == null){ //延迟实例化,亦可直接初始化静态变量,即立即实例化 instance = new Singleton(); } return instance; } } |
在多线程环境下,上述代码会实现,可以修改方法为: public synchronized static Singleton getInstance() 解决,但是添加了同步控制的方法,可能导致程序执行效率下降数十倍,因此,你可以:
- 如果 getInstance() 不会被频繁的调用,可以不用管
- 使用立即初始化方式,在类被装载的时候就实例化单例
- 使用只有单元素的枚举来实现单例,是最优化的方式
- 可以利用ClassLoader的加载机制,化立即为延迟:
123456789101112131415public class Singleton{//使用一个内部静态类,Eager方式加载单例private static class SingletonHolder{//JVM保证的线程安全性private static Singleton instance = new Singleton();}private Singleton(){}public static Singleton getInstance(){//由于类加载的同步性,下面代码可以保证获取同一个实例return SingletonHolder.instance;}} - 在JDK1.5或者更高版本,可以使用“双重检查加锁”,减少同步范围:
12345678910111213141516171819202122232425262728293031323334353637private Singleton(){}//volatile屏蔽了一些JVM代码优化://JVM不允许对volatile变量的写操作与其之前的任何读写操作进行重新排序//JVM不允许对volatile变量的读操作与其之后的任何读写操作进行重新排序private volatile static Singleton instance;public static Singleton getInstance(){if ( instance == null ){ //没有同步的情况下:后续线程可能判断instance已经不为空,而此时对象尚未实例化synchronized ( Singleton.class ){if ( instance == null )//如果没有volatile限定符,则instance = //将对象地址写到该字段与new Singleton(); //对象实例化的顺序是不可预测的/*** 下面的伪代码示意了代码编写顺序* 1 Singleton *ps = malloc(); 分配内存地址* 2 *ps = Singleton(); 调用构造函数* 3 instance = ps; 把构造完毕的对象赋值给instance** 由于volatile的语义,禁止写操作3与它前面的读写操作进行重排序,因此可以* 确保instance不为null时对象实例化已经完成** 如果没有volatile,在JVM看来2和3没有直接关联,因此可以重排序,这就导致* 了多线程下错误的语义(尽管在单线程下没有效果一样)*///加了volatile后,确保对象实例化完成后,才赋值给变量}}return instance; //后续线程可能取得了不正确的对象}
经典应用
JDK中单例
JDK中有大量单例模式的应用,例如:
1 2 3 4 5 6 |
//运行时对象 Runtime.getRuntime(); //AWT中的单例 java.awt.Toolkit.getDefaultToolkit(); java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(); java.awt.Desktop.getDesktop(); |
ExtJS中的单例
ExtJS在其类机制中内置的单例模式的支持:
1 2 3 4 5 6 7 8 |
Ext.define('Ext.Ajax', { extend: 'Ext.data.Connection', singleton: true, //声明为单例 request : function(options) {} } //对于单例的方法,可以直接使用类名调用: Ext.Ajax.request(...); |
ExtJS的API中包含很多单例,例如Ext、Ext.Ajax、Ext.data.JsonP等。
Leave a Reply