单例模式
所谓单例模式就是一个类只有一个实例。
注意点:
1、多线程之间并发考虑,保证只有一个实例创建
2、保证序列化和反序列化后依然只有一个实例
常用实现方式
1、饥饿模式
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){ } public static Singleton getInstance() { return instance; } }
关键点
- 利用在类的加载过程中 ,static变量会初始化一次。先创建好一个实例
- 提供静态方法获取此实例
- 私有构造方法
优点
- 简单明了
- 可读性好
缺点
- 实例事先创建好,可能无效的占用内存空间,并未使用(一帮情况 既然用到了此类,很大可能也要要获取此实例的)
- 反序列化会创建多个实例
2、懒汉模式(双重检查(DCL))
public class Singleton { private volatile static Singleton singleton; private Singleton (){ } public static Singleton getInstance() { if (instance== null) { synchronized (Singleton.class) { if (instance== null) { instance= new Singleton(); } } } return singleton; } }
关键点
- volatile关键字 防止CPU指令重排
- 静态方法多线程并发考虑加锁 且 双重检查
- 私有构造方法
优点
- 使用时才创建真正的实例 不浪费空间
缺点
- 代码实现稍复杂
- 不支持反序列化
3、懒汉模式(内部类实现)
public class Singleton { private Singleton(){ } public static Singleton getInstance(){ return SingletonHolder.sInstance; } private static class SingletonHolder { private static final Singleton sInstance = new Singleton(); } }
关键点
- 静态内部类的静态变量
- 私有构造方法
优点
- 对比双重检查方式 代码跟简洁 高效
缺点
- 不支持反序列化
4、枚举类型实现单例
public enum Singleton { INSTANCE; public void doSomeThing() { } }
枚举本质就是一个类 extends Enum,本质还是一个类;且默认的构造方法是private的,JVM是禁止反射调用枚举的私有构造方法
基于枚举这些特点所以说 枚举是实现单例的最佳实践。
但可读性并不友好。
优点:即使反序列化依然只有一个实例!
总结:
1、不考虑序列化的情况 优先使用第1种 或 第3种
2、出于绝对的安全考虑 请使用 枚举方式