1.饿汉式
// 问题1:为什么加 final? 防止子类修改// 问题2:如果实现了序列化接口, 还要做什么来防止反序列化破坏单例? readResolvepublic final class Singleton implements Serializable {// 问题3:为什么设置为私有? 是否能防止反射创建新的实例? 不能private Singleton() {}// 问题4:这样初始化是否能保证单例对象创建时的线程安全? 能保证,是类加载阶段完成的,由JVM保证线程安全private static final Singleton INSTANCE = new Singleton();// 问题5:为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由?// 封装性,可以懒惰初始化,也可以提供泛型支持public static Singleton getInstance() {return INSTANCE;}//如果有readResolve方法那么反序列化时会返回这个方法返回的对象public Object readResolve() {return INSTANCE;}}
2.枚举
// 问题1:枚举单例是如何限制实例个数的? 静态单实例// 问题2:枚举单例在创建时是否有并发问题?没有// 问题3:枚举单例能否被反射破坏单例?不能// 问题4:枚举单例能否被反序列化破坏单例?不能// 问题5:枚举单例属于懒汉式还是饿汉式? 饿汉式// 问题6:枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做?加构造方法enum Singleton {INSTANCE;}
3.懒汉式
public final class Singleton {private Singleton() { }private static Singleton INSTANCE = null;// 分析这里的线程安全, 并说明有什么缺点public static synchronized Singleton getInstance() {if( INSTANCE != null ){return INSTANCE;}INSTANCE = new Singleton();return INSTANCE;}}
4.DCL
public final class Singleton {private Singleton() {}// 问题1:解释为什么要加 volatile?// synchronized代码块内 INSTANCE = new Singleton()还是会发生重排序,返回了一个还没有被初始化的引用,所以需要使用volatile来禁止重排序private static volatile Singleton INSTANCE = null;// 问题2:对比实现3, 说出这样做的意义public static Singleton getInstance() {if (INSTANCE == null) {synchronized (Singleton.class) {if (INSTANCE == null) {INSTANCE = new Singleton();}}}return INSTANCE;}}
5.静态内部类
类只有在第一次被用到时触发类的加载动作
public final class Singleton {private Singleton() {}// 问题1:属于懒汉式还是饿汉式private static class LazyHolder {static final Singleton INSTANCE = new Singleton();}// 问题2:在创建时是否有并发问题public static Singleton getInstance() {return LazyHolder.INSTANCE;}}
