概念:在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
单例模式从实现上可以分为饿汉式单例和懒汉式单例两种,前者天生就是线程安全的,后者则需要考虑线程安全性,常见的线程安全的懒汉式单例的实现有内部类式和双重检查式两种。下面给出单例模式几种常见的形式:
(1)饿汉式单例
单例模式的核心有两点:
- 私有化的构造方法
- 公有化的静态的getInstance方法
/** * 恶汉式单例模式 * @author Xia */ public class Singleton { //指向自己实例的私有静态引用,主动创建 private static Singleton instance = new Singleton(); //私有的构造方法 private Singleton(){} //以自己实例为返回值的静态的公有方法,静态工厂方法 public static Singleton getInstance(){ return instance; } }
(2)懒汉式单例
懒汉式单例的核心点:
- 私有化的构造方法
- 只有在需要的时候才被创建实例
因此对于多线程而言,无法保证线程安全。
为什么无法保证线程安全呢?
我们假设有多个线程1,线程2都需要使用这个单例对象。而恰巧,线程1在判断完instance==null后突然交换了cpu的使用权,变为线程2执行,由于instance仍然为null,那么线程2中就会创建这个Singleton的单例对象。之后线程1拿回cpu的使用权,而正好线程1之前暂停的位置就是判断instance是否为null之后,创建对象之前。这样线程1又会创建一个新的Singleton对象。
/** * 懒汉式单例模式 * @author Xia */ public class Singleton2 { //指向自己实例的私有静态引用 private static Singleton2 instance ; //私有的构造方法 private Singleton2(){} //以自己实例为返回值的静态的公有方法,静态工厂方法 public static Singleton2 getInstance(){ // 被动创建,在真正需要使用时才去创建 if (instance == null) { instance = new Singleton2(); } return instance; } }
(3)线程安全的懒汉式单例——双重检查方式
上面我们提到,懒汉式的单例模式因为其创建是在需要的时候才new出来,中间可能会被打断,因此,需要用Synchronized关键字将对象锁定。
/** * 线程安全的懒汉式单例模式 * @author Xia */ public class Singleton3 { //指向自己实例的私有静态引用 private static Singleton3 instance ; //私有的构造方法 private Singleton3(){} //以自己实例为返回值的静态的公有方法,静态工厂方法 public static Singleton3 getInstance(){ // 第一次检查 if (instance == null) { //锁定该类对象 synchronized (Singleton3.class) { //第二次检查 if (instance == null) { instance = new Singleton3(); } } } return instance; } }