单例设计模式提供了一种在多线程环境下保证 实例唯一性 的解决方案。从线程安全、高性能、懒加载三个维度进行分析,推荐使用 Holder方式 或者 枚举方式 实现单例模式


前言

  • 单例模式的优缺点对比: | 设计模式 | 线程安全 | 性能 | 懒加载 | | —- | —- | —- | —- | | 饿汉式 | 是 | 较高 | 否 | | 懒汉式 | 否 | 较高 | 是 | | 懒汉式 + 同步方法 | 是 | 低 | 是 | | Double Check | 是,但易出现空指针异常 | 高 | 是 | | Double Check + Volatile | 是 | 高 | 是 | | Holder方式 | 是 | 高 | 是 | | 枚举方式 | 是 | 高 | 是 |

1.Holder方式

  1. public class HolderSingleton {
  2. private HolderSingleton() {
  3. super();
  4. }
  5. /** 静态内部类 */
  6. private static class Holder {
  7. private static HolderSingleton instance = new HolderSingleton();
  8. }
  9. /** 获取 Holder 类的静态变量,主动使用实现初始化 */
  10. public static HolderSingleton getInstance() {
  11. return Holder.instance;
  12. }
  13. }

解释:HolderSingleton 类中没有 instance 的静态成员变量,而是放在了静态内部类 Holder 之中,因此 Singleton 类的初始化过程中并不会创建 Singleton 的实例。当 Holder 被 主动使用 的时候会创建 Singleton 的实例。同时 Singleton 实例的创建过程在 Java 程序编译时期收集到了 () 方法中,() 方法是同步方法,保证了内存的可见性、JVM指令的顺序性和原子性。

2.枚举方式

  1. public class EnumSingletom {
  2. private EnumSingletom() {
  3. super();
  4. }
  5. /** 使用枚举类代替 holder,增加懒加载特性 */
  6. private enum EnumHolder {
  7. INSTANCE;
  8. private EnumSingletom instance;
  9. EnumHolder() {
  10. this.instance = new EnumSingletom();
  11. }
  12. private EnumSingletom getInstance() {
  13. return instance;
  14. }
  15. }
  16. /** 主动使用触发枚举类的实例化(有且仅有一次) */
  17. public static EnumSingletom getInstance() {
  18. return EnumHolder.INSTANCE.getInstance();
  19. }
  20. }

解释:枚举类型本身是 final 类型的,不允许被继承。同时枚举类型是线程安全的并且只能被实例化一次。通过将 枚举类 替代 Holder 的方式,可以实现 instance 实例的懒加载。