设计模式-单例模式
返回上一级目录:Java设计模式
单例模式,所谓单例,就是应用只有一个实例对象,该类具有以下特点:
- 构造器私有化,保证只有自己才能通过构造器创建实例对象
- 持有实例对象的引用,就是最终提供出去的单例实例
- 提供一个方法获取该单例实例
下面是常用的几种实现:
1、懒汉式
这是最简单也最容易想到的一种方式。缺点就是不是线程安全,多个线程环境下可能会生成多个实例对象。
public class Singleton1 { private static Singleton1 instance; /** * 构造方法私有化 */ private Singleton1() { } public static Singleton1 getInstance() { if (instance == null) { instance = new Singleton1(); } return instance; } }
2、懒汉式(线程安全)
鉴于懒汉式的缺点,一个改进的方法就是在对getInstance()加锁,确保同时只有一个线程调用。
public class Singleton2 { private static Singleton2 instance; /** * 构造方法私有化 */ private Singleton2() { } /** * 弥补了SimpleSingleton1线程安全问题,但是效率很低,任何时候需要instance只能有一个线程去访问getInstance(), * 其实只需要在第一次创建对象时候同步,保证只有一个实例被创建 * * @return */ public static synchronized Singleton2 getInstance() { if (instance == null) { instance = new Singleton2(); } return instance; } }
3、双重校验锁
这种方式能很好的解决了懒汉式线程安全和效率的问题,实际应用中通常推荐使用这种方式。
public class Singleton3 { /** * volatile是禁止new Singleton3()发生指令重排序 * instance = new Singleton3()在jvm中做了3件事:1.分配内存,2.调用构造方法初始化成员变量,3.将instance指向分配的内存空间 * jvm在编译时可能对上面步骤2,3重排序,如果先执行3,这时候instance != null,可能被其他线程拿到一个没有初始化完的对象使用而出错 */ private static volatile Singleton3 instance; private Singleton3() { } /** * 多个线程进入第一个if,只有一个线程进入同步块创建对象,如果其他线程获得锁进入同步块,不判断instance是否已经被创建, * 则有可能会创建多个对象 * * @return */ public static Singleton3 getInstance() { if (instance == null) { synchronized (Singleton3.class) { if (instance == null) { instance = new Singleton3(); } } } return instance; } }
4、饿汉式
一开始就初始化好一个静态的实例,在其他调用者需要时直接返回。缺点是创建比较简单,不能依赖其他的参数来创建实例对象。
public class Singleton4 { private static Singleton4 instance = new Singleton4(); private Singleton4() { } /** * 类加载后就被初始化,不能依赖其他参数来创建实例 * * @return */ public static Singleton4 getInstance() { return instance; } }
5、静态内部类
静态内部类不会随着外部类加载而加载,当getInstance()被调用时,内部类SingletonHolder被加载,接着其静态属性instance初始化。这样不仅保证了延迟加载,也保证了线程安全,也经常被推荐使用。
public class Singleton5 { private Singleton5() { } private static class SingletonHolder { private static Singleton5 instance = new Singleton5(); } /** * 使用SingletonHolder时候才会加载内部静态类,所以也是懒汉式,类加载机制又保证了多线程的安全性 * * @return */ public static Singleton5 getInstance() { return SingletonHolder.instance; } }