/**
 * 单例模式,懒汉式,线程不安全
 */
public class Singleton {
    private static Singleton uniqueInstance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}
/**
* 单例模式,饿汉式,线程安全
*/
public class Singleton2 {
    private static Singleton2 instance  = new Singleton2();

    private Singleton2() {}

    public static Singleton2 getInstance() {
        if (instance == null) {
            instance = new Singleton2();
        }

        return instance;
    }
}
/**
* 单例模式,饿汉式,线程安全,多线程环境下效率不高
*/
public class Singleton3 {
    private static Singleton3 instance = null;

    private Singleton3() {}

    public static synchronized Singleton3 getInstance() {
        if (instance == null) {
            instance = new Singleton3();
        }

        return instance;
    }
}
/**
 * 单例模式,饿汉式,由 static 块保证线程安全
 */
public class Singleton4 {
    private static Singleton4 instance;

    static {
        instance = new Singleton4();
    }

    private Singleton4() {}

    public static Singleton4 getInstance() {
        return instance;
    }
}
/**
 * 单例模式,懒汉式,使用静态内部类,线程安全【推荐】
 */
public class Singleton5 {

    private class SingletonHolder {
        private static final Singleton5 INSTANCE = new Singleton5();
    }

    private Singleton5() {}

    public static Singleton5 getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
/**
* 使用枚举方式,线程安全【推荐】
*
* 枚举自己处理序列化
*/
public enum Singleton6 {
    //调用 Singleton6.INSTANCE.whateverMethod()
    INSTANCE

    public void whateverMethod() {
    }
}
/**
 * 使用双重校验锁,线程安全【推荐】
 */
public class Singleton7 {
    private volatile static Singleton7 instance = null;

    private Singleton7() {}

    public static Singleton7 getInstance() {
        if (instance == null) {
            synchronized (Singleton7.class) {
                if (instance == null) {
                    instance = new Singleton7();
                }
            }
        }

        return instance;
    }
}

小结

推荐:静态内部类、枚举、双重校验锁

最好的单例模式:枚举

枚举

使用枚举实现单例模式是最好的方法,因为

  1. 写法简单

    public enum Singleton6 {
        //调用 Singleton6.INSTANCE.whateverMethod()
        INSTANCE
    
        public void whateverMethod() {
        }
    }
    
  2. 枚举实例创建是线程安全的

    当一个Java类第一次被真正使用到的时候,静态资源被初始化。Java类的加载和初始化过程都是线程安全的。enum类型会被编译器编译成class T extends Enum的类。所以,创建一个enum类型是线程安全的。

  3. 枚举自己处理序列化

    普通的Java类的反序列化过程中,会通过反射调用类的默认构造函数来初始化对象。所以,即使单例中构造函数是私有的,也会被反射给破坏掉。由于反序列化后的对象是重新new出来的,所以这就破坏了单例。但是,枚举的反序列化并不是通过反射实现的。所以,也就不会发生由于反序列化导致的单例破坏问题。

    关于枚举类的序列化和反序列化:在序列化的时候Java仅仅是将枚举对象的属性输出到结果中,反序列化的时候则是通过java.lang.EnumvalueOf方法来根据名字查找枚举对象。同时,编译器不允许对这种序列化机制进行定制,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。

双重校验锁

volatile 关键字的含义: - 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,新值对其他线程是立即可见的 - 禁止进行指令重排序

volatile 关键字在本实现的主要作用:禁止进行指令重排序。因为类初始化分两步: volatile 的不足:无法保证原子性,所以要结合synchronized实现

volatile 的使用条件: - 对变量的写操作不依赖于当前值 - 该变量没有包含在具有其他变量的不变式中 (a <= b)

静态内部类