vlambda博客
学习文章列表

Java基础—单例模式

1. 懒汉式,线程不安全

    public class Singleton {

     private static Singleton INSTANCE;

     private Singleton() {}

     public static Singleton getInstance() {

     if (INSTANCE == null) {

     INSTANCE = new Singleton();

     }

     return INSTANCE;

     }

    }

2. 懒汉式, 线程安全

    public class Singleton {

     private static Singleton INSTANCE;

     private Singleton() {}

     public static synchronized Singleton getInstance() {

     if (INSTANCE == null) {

     INSTANCE = new Singleton();

     }

     return INSTANCE;

     }

    }

3. 饿汉式

    public class Singleton {

     private static Singleton INSTANCE = new Singleton();

     private Singleton() {}

     public static Singleton getInstance() {

     return INSTANCE;

     }

    }

4. 双重校验,double-checked locking

    public class Singleton {

     private static volatile Singleton INSTANCE;

     private Singleton() { }

     public static Singleton getInstance() {

     if (INSTANCE == null) {

     synchronized (Singleton.class) {

     INSTANCE = new Singleton();

     }

     }

     return INSTANCE;

     }

    }

5. 静态内部类

    public class Singleton {

     private static class SingletonHolder {

private final static Singleton INSTANCE = new Singleton    ();

     }

    private Singleton() { }

     public static Singleton getInstance() {

    return SingletonHolder.INSTANCE;

     }

    }

6. 枚举

    public enum Singleton {

     INSTANCE

    }

  • 不推荐使用第1种和第2种 懒汉式,可以使用第3种 饿汉式,需要懒加载可以使用第4种 双重校验和第5种 静态内部类,如果涉及到反序列化创建对象需要用第6种 枚举去实现。

  • 双重校验的 volatile关键字不可缺失,保证初始化三步骤不会被指令优化重排。三步骤是:1)分配空间 2)初始化值 3)将对象指向刚分配的空间。正常为1-2-3,重排变成1-3-2

  • 静态内部类利用classloader机制,在静态内部类没有访问的时候, INSTANCE是不会被初始化的,而静态内部类只会被加载一次。

  • 枚举为最佳单例实现方式。简洁,反序列化后仍然是同一实例, Constructor类的 newInstance方法有判定对enum的类反射会抛出异常。(enum本质上是一个抽象类,新建一个枚举类就是继承了enum这个抽象类,只能用enum的构造方案)

    if ((clazz.getModifiers() & Modifier.ENUM) != 0)

       throw new IllegalArgumentException("Cannot reflectively create enum objects");