单例模式
-
设计思路
- 实例化过程
- 提供返回实例的方法
-
需要考虑的问题
- 线程安全性
- 性能
- 懒加载(Lazy)
-
饿汉式(基于 ClassLoader 机制避免了多线程问题;没有懒加载效果)
private static HungerSingleton hungerSingleton = new HungerSingleton(); private HungerSingleton() { } public static HungerSingleton getInstance() { return hungerSingleton; } /** * 1、类加载时即完成实例化,不存在线程安全问题 * 2、性能较好 * 3、初始化时加载到内存中,长时间不用时影响性能(内存中成员变量较多时) **/
-
懒汉式(实现了懒加载,但线程不安全;使用 synchronized – 效率太低)
private static LazySingleton singleton = null; private LazySingleton() {} public static (synchronized) LazySingleton getInstance() { if (null == singleton) { singleton = new LazySingleton(); } } /** * 1、线程不安全 * 2、使用时才加载,内存友好 **/
-
懒汉式+同步(不安全)
private static LazySingleton singleton = null; private LazySingleton() { } public static LazySingleton getInstance() { if (null == singleton) { // 如果存在多个线程同时进入此 if 判断,一个线程实例化完成后,另外一个线程获得锁后也可以完成实例化 synchronized (LazySingleton.class) { singleton = new LazySingleton(); } } return singleton; }
-
懒汉式+同步(Double Check Lock)
private static DCLSingleton singleton = null; private DCLSingleton() { } public static DCLSingleton getInstance() { if (null == singleton) { synchronized (DCLSingleton.class) { if (null == singleton) { // 虚拟机可能会对新建对象指令进行重排,可能导致其他线程提前获取到未初始化完成的对象 singleton = new DCLSingleton(); } } } return singleton; }
-
懒汉式+同步优化
// DCL 模式优化:添加 volatile 修饰禁止指令重排 private volatile static DCLSingleton singleton = null;
-
内部类(推荐)
public class HolderInstance { private HolderInstance() {} // 静态内部类的方法被显示调用才会触发初始化 private static class Holder { private static HolderInstance instance = new HolderInstance(); public static HolderInstance getInstance() { return Holder.instance; } } }
前几种单例模式总结:
- 构造方法私有化 – 私有化构造器并不保险,无法抵御反射攻击
- 实例化的变量引用私有化
- 获取实例的方法共有
-
枚举实现(强烈推荐)
// 直接将需要实现单例的类定义为Enum即可 public enum Singleton{ INSTANCE; // 包含一个隐式的构造函数;INSTANCE是所属的Enum类型;内部也可以定义方法 // TODO all the method you want }
枚举单例模式总结:
- 反射安全(JDK禁止反射实例化枚举)
- (反)序列化安全
- 写法简单