1.饿汉式

  1. // 问题1:为什么加 final? 防止子类修改
  2. // 问题2:如果实现了序列化接口, 还要做什么来防止反序列化破坏单例? readResolve
  3. public final class Singleton implements Serializable {
  4. // 问题3:为什么设置为私有? 是否能防止反射创建新的实例? 不能
  5. private Singleton() {}
  6. // 问题4:这样初始化是否能保证单例对象创建时的线程安全? 能保证,是类加载阶段完成的,由JVM保证线程安全
  7. private static final Singleton INSTANCE = new Singleton();
  8. // 问题5:为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由?
  9. // 封装性,可以懒惰初始化,也可以提供泛型支持
  10. public static Singleton getInstance() {
  11. return INSTANCE;
  12. }
  13. //如果有readResolve方法那么反序列化时会返回这个方法返回的对象
  14. public Object readResolve() {
  15. return INSTANCE;
  16. }
  17. }

2.枚举

  1. // 问题1:枚举单例是如何限制实例个数的? 静态单实例
  2. // 问题2:枚举单例在创建时是否有并发问题?没有
  3. // 问题3:枚举单例能否被反射破坏单例?不能
  4. // 问题4:枚举单例能否被反序列化破坏单例?不能
  5. // 问题5:枚举单例属于懒汉式还是饿汉式? 饿汉式
  6. // 问题6:枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做?加构造方法
  7. enum Singleton {
  8. INSTANCE;
  9. }

3.懒汉式

  1. public final class Singleton {
  2. private Singleton() { }
  3. private static Singleton INSTANCE = null;
  4. // 分析这里的线程安全, 并说明有什么缺点
  5. public static synchronized Singleton getInstance() {
  6. if( INSTANCE != null ){
  7. return INSTANCE;
  8. }
  9. INSTANCE = new Singleton();
  10. return INSTANCE;
  11. }
  12. }

4.DCL

  1. public final class Singleton {
  2. private Singleton() {}
  3. // 问题1:解释为什么要加 volatile?
  4. // synchronized代码块内 INSTANCE = new Singleton()还是会发生重排序,返回了一个还没有被初始化的引用,所以需要使用volatile来禁止重排序
  5. private static volatile Singleton INSTANCE = null;
  6. // 问题2:对比实现3, 说出这样做的意义
  7. public static Singleton getInstance() {
  8. if (INSTANCE == null) {
  9. synchronized (Singleton.class) {
  10. if (INSTANCE == null) {
  11. INSTANCE = new Singleton();
  12. }
  13. }
  14. }
  15. return INSTANCE;
  16. }
  17. }

5.静态内部类

类只有在第一次被用到时触发类的加载动作

  1. public final class Singleton {
  2. private Singleton() {}
  3. // 问题1:属于懒汉式还是饿汉式
  4. private static class LazyHolder {
  5. static final Singleton INSTANCE = new Singleton();
  6. }
  7. // 问题2:在创建时是否有并发问题
  8. public static Singleton getInstance() {
  9. return LazyHolder.INSTANCE;
  10. }
  11. }