1、懒汉式,线程不安全

  • Lazy 初始化,多线程不安全,实现难度低

    1. public class Singleton {
    2. private static Singleton instance;
    3. private Singleton (){}
    4. public static Singleton getInstance() {
    5. if (instance == null) {
    6. instance = new Singleton();
    7. }
    8. return instance;
    9. }
    10. }

    2、懒汉式,线程安全

  • Lazy 初始化,多线程安全,实现难度低

  • 优点:第一次调用才初始化,避免内存浪费
  • 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率

    1. public class Singleton {
    2. private static Singleton instance;
    3. private Singleton (){}
    4. public static synchronized Singleton getInstance() {
    5. if (instance == null) {
    6. instance = new Singleton();
    7. }
    8. return instance;
    9. }
    10. }

    3、饿汉式

  • 不是 Lazy 初始化,多线程安全,实现难度低

  • 优点:没加锁,执行效率高
  • 缺点:类加载时就初始化,浪费内存
  • 基于 classloader 机制避免多线程同步问题,instance 在类装载时就实例化,导致类装载的原因有很多,在单例模式中大多是调用 getInstance, 但也不能确定有其他方式(或静态方法)导致类装载,这时初始化 instance 没达到 lazy loading 效果

    1. public class Singleton {
    2. private static Singleton instance = new Singleton();
    3. private Singleton (){}
    4. public static Singleton getInstance() {
    5. return instance;
    6. }
    7. }

    4、双检锁/双重校验锁(DCL,double-checked locking)

  • Lazy 初始化,多线程安全,实现难度较复杂

    1. public class Singleton {
    2. private volatile static Singleton singleton;
    3. private Singleton (){}
    4. public static Singleton getSingleton() {
    5. if (singleton == null) {
    6. synchronized (Singleton.class) {
    7. if (singleton == null) {
    8. singleton = new Singleton();
    9. }
    10. }
    11. }
    12. return singleton;
    13. }
    14. }

    5、登记式/静态内部类

  • Lazy 初始化,多线程安全,实现难度低

  • 只适用于静态域情况,双检锁方式可在实例域需要延迟初始化时使用
  • 利用了 classloader 机制保证初始化 instance 时只有一个线程,跟饿汉式不同,饿汉式只要 Singleton 类被装载,instance 就被实例化(没达到 lazy loading 效果),而该方式是 Singleton 类被装载,instance 不一定被初始化,因为 SingletonHolder 类没被主动使用,只有通过显式调用 getInstance 方法时才会显式装载 SingletonHolder 类从而实例化 instance

    1. public class Singleton {
    2. private static class SingletonHolder {
    3. private static final Singleton INSTANCE = new Singleton();
    4. }
    5. private Singleton (){}
    6. public static final Singleton getInstance() {
    7. return SingletonHolder.INSTANCE;
    8. }
    9. }

    6、枚举

  • 不是 Lazy 初始化,多线程安全,实现难度低

  • 实现单例模式的最佳方法,更简洁,自动支持序列化机制,绝对防止多次实例化
  • 不能通过 reflection attack 调用私有构造方法
    1. public enum Singleton {
    2. INSTANCE;
    3. public void whateverMethod() {}
    4. }

    一般不建议使用前两中懒汉式,建议使用饿汉式。只在明确实现 lazy loading 效果时才使用登记式。如果涉及反序列化创建对象,可用枚举式。如有其他特殊需求,可用双检锁式