定义:确保某一个类只有单一的实例,而且自行实例化,向整个系统提供一个实例,这个类叫单例类,提供全局的访问方法。
单例模式有三个要点:
1、某个类只能有一个实例
2、它必须自行创建这个实例
3、必须自行向整个系统提供这个实例
单例类在消耗资源较大的重型对象中使用较多,如数据库连接的CollectionPool对象,Hibernate中的Configuration对象。Windows上的资源管理器也是由单例模式实现的(只能打开一个资源管理器)。
Singleton的一般实现
1 Class Singleton{ 2 private static Singleton instance=null; 3 private Singleton(){} 4 public static Singleton getInstance(){ 5 if(instance==null){ 6 instance=new Singleton(); 7 } 8 return instance; 9 } 10 }
以上代码,在单线程的环境下不会有什么问题,但当多个线程同时访问时(由于单例类一般需要大量初始化工作),可能会导致在没有完全初始化之前,其他线程已经进行if语句判断,并为true。这样的情况会出现多个单例类的实例
线程不安全Singleton的解决方案:
A:EagerSingleton:饿汉单例模式,单例对象的初始化在类加载的时候完成
1 class EagerSingleton{ 2 //同理,亦可以使用static代码块实现初始化 3 private static EagerSingleton instance= new EagerSingleton(); 4 private EagerSingleton(){} 5 public static EagerSingleton getInstance(){ 6 return instance; 7 } 8 }
以上代码,虽然解决了线程安全问题,但是,类加载的时间会延长
B:LazySingleton:懒汉单例模式,利用synchronized对getInstance方法进行线程锁定
1 class LazySingleton{ 2 private static LazySingleton instance=null; 3 private LazySingleton(){} 4 synchronized public static LazySingleton getInstance(){ 5 if(instance==null){ 6 instance=new LazySingleton(); 7 } 8 return instance; 9 } 10 }
以上代码,可以很好的解决线程安全问题,而且也使用了延迟加载技术,但是每次调用getInstance都需要进行线程锁定判断,大大降低了系统性能
C:Double-Check Locking:双重检查锁定,利用volatile保证多线程下对成员变量的正确处理,在利用双重判断加同步实现LazySingleton
1 class LazySingleton{ 2 private volatile static LazySingleton instance=null; 3 private LazySingleton(){} 4 synchronized public static LazySingleton getInstance(){ 5 if(instance==null){ 6 synchronized(LazySingleton.class){ 7 if(instance==null){ 8 instance=new LazySingleton(); 9 } 10 } 11 } 12 return instance; 13 } 14 }
以上代码,同样对系统的性能有影响,而且volatile会屏蔽虚拟机的一些代码优化
D:IoDH:使用静态内部类实现延迟加载及线程安全
1 class Singleton{ 2 private Singleton(){} 3 private static class Hoder{ 4 private final static Singleton instance=new Singleton(); 5 } 6 public static Singleton getInstance(){ 7 return Holder.instance; 8 } 9 }
以上代码,既可以保证延迟加载,又可以保证线程安全,不影响系统性能,实际上,采用内部类的方法可以将实例化及返回封装成原子操作,这样就完全不需要考虑线程安全问题了,综上所述,这是一种较好的单例模式实现方法
E:单元素的枚举类型:Effective java中提及,实现Singleton的最佳方法
更加简洁,无偿提供了序列化机制,绝对防止多次实例化,即使是在面对复杂序列化或者反射攻击的时候。虽然这种方法还没有广泛使用。。。所以,笔者不提倡。。。
----------------------------------------------------------------------------------------------------------------------------------------------------------------
不足之处,还望指正