单例的作用
单例的适用场景
无状态的工具类
全局信息类
单例的8种写法
饿汉式(静态常量)【可用】
/*** 描述: 饿汉式(静态常量)(可用)*/public class Singleton1 {private final static Singleton1 INSTANCE = new Singleton1();private Singleton1() {}public static Singleton1 getInstance() {return INSTANCE;}}
饿汉式(静态代码块)【可用】
/*** 描述: 饿汉式(静态代码块)(可用)*/public class Singleton2 {private final static Singleton2 INSTANCE;static {INSTANCE = new Singleton2();}private Singleton2() {}public static Singleton2 getInstance() {return INSTANCE;}}
懒汉式(线程不安全)【不可用】
/*** 描述: 懒汉式(线程不安全)*/public class Singleton3 {private static Singleton3 instance;private Singleton3() {}public static Singleton3 getInstance() {if (instance == null) {instance = new Singleton3();}return instance;}}
懒汉式(线程安全,同步方法)【不推荐用】
/*** 描述: 懒汉式(线程安全)(不推荐)*/public class Singleton4 {private static Singleton4 instance;private Singleton4() {}public synchronized static Singleton4 getInstance() {if (instance == null) {instance = new Singleton4();}return instance;}}
懒汉式(线程不安全,同步代码块)【不可用】
/*** 描述: 懒汉式(线程不安全)(不推荐)*/public class Singleton5 {private static Singleton5 instance;private Singleton5() {}public static Singleton5 getInstance() {if (instance == null) {synchronized (Singleton5.class) {instance = new Singleton5();}}return instance;}}
懒汉式(双重检查)【推荐】
/*** 描述: 双重检查(推荐面试使用)*/public class Singleton6 {private volatile static Singleton6 instance;private Singleton6() {}public static Singleton6 getInstance() {if (instance == null) {synchronized (Singleton6.class) {if (instance == null) {instance = new Singleton6();}}}return instance;}}
为什么要double-check
重点解释
“在第一个线程退出synchronized之前,里面的操作执行了一部分,比如执行了new却还没执行构造函数,然后第一个线程被切换走了,这个时候第二个线程刚刚到第一重检查,所以看到的对象就是非空,就跳过了整个synchronized代码块,获取到了这个单例对象,但是使用其中的属性的时候却不是想要的值。”

静态内部内【推荐用】
/*** 描述: 静态内部类方式,可用*/public class Singleton7 {private Singleton7() {}private static class SingletonInstance {private static final Singleton7 INSTANCE = new Singleton7();}public static Singleton7 getInstance() {return SingletonInstance.INSTANCE;}}
枚举【推荐】
/*** 描述: 枚举单例*/public enum Singleton8 {INSTANCE;public void whatever() {}}
不同写法对比
- 饿汉:简单,但是没有懒加载
- 懒汉:有线程安全问题
- 静态内部内:可用
- 双重检查:面试用
- 枚举:最好
为什么枚举最好?
- 写法简单
- 线程安全、懒加载 (枚举是一种特殊类,枚举会被编译成 final class,然后继承枚举这个父类,它的各个实例都是通过static定义的,枚举本质就是静态的对象,在第一使用到枚举实例时,才会加载进来)
- 避免反射、反序列化破坏单例
