单例模式

113 阅读2分钟

单例模式

饿汉式(Eager Singleton)

  • 在类装载的时候就创建对象实例
  • 使用场景:java.lang.Runtime
public class Singleton {
    // 本类中创建 private static final 修饰的本类对象实例
    private static final Singleton instance = new Singleton();
    // 私有化构造器
    private Singleton() {}
    // 提供一个 public static 修饰的方法返回此对象实例
    public static Singleton getInstance() {
        return instance;
    }
}
public class Singleton {
    // 私有化构造器
    private Singleton() {}
    // 静态内部类不会在单例类加载时就加载,而是在调用 getInstance() 方法时才进行加载
    private static class SingletonHolder {
        private static Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

懒汉式 / 懒加载(Lazy Singleton)

  • 每次获取实例都会进行判断,看是否需要创建实例(线程不安全
  • “双重检查加锁”机制:不是每次进入 getInstance() 方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。
public class Singleton {
    // 本类中定义 private static volatile 修饰的、引用为空的类变量
    private static volatile Singleton instance = null;
    // 私有化构造器
    private Singleton() {}
    // 提供一个 public static 修饰的方法返回对象实例
    public static Singleton getInstance() {
        // 先检查实例是否存在,如果不存在才进入下面的同步块
        if (instance == null) {
            synchronized (Singleton.class) {
                // 双重检测锁:再次检查实例是否存在,如果不存在才真正的创建实例
                 if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

使用枚举类做单例模式(较推荐)

  • 定义一个包含单个元素的枚举类型
  • 这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。 这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。 不能通过 reflection attack 来调用私有构造方法。
public enum Singleton {
    INSTANCE;
}
// 调用
Singleton.INSTANCE.sort(null);