单例模式
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类 单例模式的特点: 单例类只能有一个实例。 单例类必须自己创建自己的唯一实例。 单例类必须给所有其他对象提供这一实例。
- 饿汉式单例类
/** * 饿汉式单例类 */ public class EagerSingleton { private static EagerSingleton singleton=new EagerSingleton(); /** * 私有默认构造函数 */ private EagerSingleton(){} /** * 静态工厂方法 * @return */ public static EagerSingleton getInstance(){ return singleton; } }
类被加载时,静态变量初始化,调用默认构造器,那么单例类的唯一实例就被创建出来了。饿汉式是典型的空间换时间
- 懒汉式单例类
/** * 懒汉式单例类 * @author 开发 */ public class LazySingleton { private static LazySingleton singleton; /** * 私有默认构造函数 */ private LazySingleton(){} /** * 静态工厂方法 * @return */ public static synchronized LazySingleton getInstance(){ if(singleton==null){ singleton=new LazySingleton(); } return singleton; } }
上面的懒汉式单例类实现了对静态工厂方法同步化,以处理多线程环境。懒汉式是时间换空间(线程安全)
- 双重检查加锁
/** * 双重检查加锁 * @author 开发 * */ public class Singleton { private volatile static Singleton instance=null; private Singleton(){} @SuppressWarnings("unused") private static Singleton getInstance(){ //先检查实例是否存在,如果不存在才进入下面的同步块 if(instance==null){ //同步块,线程安全的创建实例 synchronized (Singleton.class) { //再次检查实例是否存在,如果不存在才真正的创建实例 if(instance==null){ instance=new Singleton(); } } } return instance; } }
所谓“双重检查加锁”机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。
“双重检查加锁”机制的实现会使用关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
由于volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高。因此一般建议,没有特别的需要,不要使用。也就是说,虽然可以使用“双重检查加锁”机制来实现线程安全的单例,但并不建议大量采用,可以根据情况来选用。