【我的设计模式学习】单例模式
单例模式大概是最直观的一种设计模式了。尽管直观却不简单。
数学与逻辑学中,singleton定义为“有且仅有一个元素的集合”。单例模式可以如下定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供”。
我比较喜欢Design Patterns 一书中的描述"保证一个类仅有一个实例,并提供一个访问它的全局访问点"。
单例模式的特点
1、单例类只能有一个实例。
2、单例类必须自己自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
最经典的实现
实现单例,可以将类的构造方法限定为private,避免在外部实例化,然后在类中提供一个静态的实例并能够返回给使用者,在同一个虚拟机范围内,Singleton的唯一实例
只能通过getInstance方法访问。
public class Singleton { /** * classic singleton * realize lazy loaded 添加判断uniqueInstance是否初始化,实现了使用时才进行加载 */ private static Singleton uniqueInstance=null; private Singleton(){ //Exits only to defeat instantiation } public static Singleton getInstance(){ if(uniqueInstance==null){ uniqueInstance =new Singleton(); } return uniqueInstance; } }
线程安全的实现
上面的实现方法并没有考虑多线程的环境,试想存在两个线程A和B,同时调用getInstance方法,线程A检查uniqueInstance是null,开始创建实例;同时线程B检测到
uniqueInstance是null,于是线程A/B各自创建了对象。
解决的最简单方法是加锁,为getInstance的静态方法添加synchronized关键字。但是考虑到Synchronized对性能影响较大(http://www.infoq.com/cn/articles/java-se-16-synchronized),
可以调整Synchronized添加(加锁)的位置。
public class Singleton { private static Singleton uniqueInstance=null; private Singleton(){ //Exits only to defeat instantiation } /** * Thread safe * 判断instance是不是为null,如果为null,加锁初始化;如果不为null,直接返回instance */ public static Singleton getInstanceSafe(){ if(uniqueInstance==null){ synchronized(Singleton.class){ if(uniqueInstance==null){ uniqueInstance=new Singleton(); } } } return uniqueInstance; } }
饿汉式 懒汉式和登记式
另外,一些文档会提到单例模式的三种形式(懒汉式,饿汉式,登记式),其实饿汉式和懒汉式主要是线程安全的区别,同时懒汉式是延时加载,
在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,上面已经提到,例如下面代码。
而登记式单例可以参考Spring创建Bean时的单例模式(http://blog.csdn.net/arvinrong/article/details/7756167)。
//饿汉式单例类.在类初始化时,已经自行实例化 public class Singleton1 { //私有的默认构造子 private Singleton1() {} //已经自行实例化 private static final Singleton1 single = new Singleton1(); //静态工厂方法 public static Singleton1 getInstance() { return single; } }
//懒汉式单例类.在第一次调用的时候实例化 public class Singleton2 { //私有的默认构造子 private Singleton2() {} //注意,这里没有final private static Singleton2 single=null; //静态工厂方法 public synchronized static Singleton2 getInstance() { if (single == null) { single = new Singleton2(); } return single; } }