单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池,缓存,日志对象,对话框等常被设计成单例
单例模式的特点:1.单例类智能有一个实例.
2.单例类必须自己创建自己的唯一实例.
3.单例类必须给其他对象提供这一实例.
实现单列的5种方式 懒汉式:默认不会实例化,第一次使用的时候实例化.(可能会由有线程安全问题) 1. 双重检查,已解决线程安全问题【推荐使用】public class Singleton4 { private static volatile Singleton4 singleton; private Singleton4() { } public static Singleton4 getInstance() { if (singleton == null) { synchronized (Singleton4.class) { if (singleton == null) { singleton = new Singleton4(); } } } return singleton; }}
2.静态内部类 【推荐使用】public class Singleton5 { private Singleton5() { } // 静态内部类 public static class Singleton5Instance { private static final Singleton5 INSTANCE = new Singleton5(); } public static Singleton5 getInstance() { return Singleton5Instance.INSTANCE; }}
饿汉式 : 默认实例化 (类加载的时候实例化 无线程安全问题) 1.静态常量【可用】public class Singleton { private final static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; }}
2.静态代码块【可用】public class Singleton2 { private static Singleton2 INSTANCE; private Singleton2() { } static { INSTANCE = new Singleton2(); } public static Singleton2 getInstance() { return INSTANCE; }}
3.枚举【推荐使用】public class Singleton6 { public Singleton6() { } public static Singleton6 getInstance() { return SingletonEnum.INSTANCE.getSingleton(); } private enum SingletonEnum { INSTANCE; private Singleton6 singleton; SingletonEnum() { singleton = new Singleton6(); } private Singleton6 getSingleton() { return singleton; } }}
单例模式的破坏以及解决办法 (反射/反序列化)除枚举外,其他的方法都可以通过反射的方式破坏单例模式 反射是通过调用构造方法生成新的对象,如果想要阻止单例被破坏,可以在构造方法中进行判断.
private Singleton4() { if (singleton != null) { throw new RuntimeException("实例已经存在,请通过 getInstance()方法获取"); } }
如果单例类实现了Serializable, 就可以通过反序列化破坏单例.解决办法是在单例类中添加反序列化方法readResolve
public class Singleton5 { private Singleton5() { } // 静态内部类 public static class Singleton5Instance { private static final Singleton5 INSTANCE = new Singleton5(); } public static Singleton5 getInstance() { return Singleton5Instance.INSTANCE; } // 防止反序列化破坏单例模式 public Object readResolve() { return Singleton5Instance.INSTANCE; }}
添加readResolve 方法,方法中返回实例的逻辑与单例类提供的获取实例的逻辑一模一样.