首页 > 其他分享 >了解单例模式

了解单例模式

时间:2022-08-25 19:14:59浏览次数:93  
标签:IdGenerator private instance 了解 模式 单例 new public

单例模式

单例模式是什么?

单例设计模式(Singleton Design Pattern)如果一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。

为什么要用单例模式?
  1. 两个线程同时作用于一个共享变量,有可能发生覆盖。
  2. 有些数据在系统中只应保存一份
如何实现单例?
  • 构造函数需要是 private 访问权限的,这样才能避免外部通过 new 创建实例;
  • 考虑对象创建时的线程安全问题;
  • 考虑是否支持延迟加载;
  • 考虑是否支持延迟加载;
  • 考虑 getInstance() 性能是否高(是否加锁)。
1.饿汉式

​ 在类加载的时候,instance 静态实例就已经创建并初始化好了,所以,instance 实例的创建过程是线程安全的。不过,这样的实现方式不支持延迟加载(在真正用到 IdGenerator 的时候,再创建实例)

public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private static final IdGenerator instance = new IdGenerator();
  private IdGenerator() {}
  public static IdGenerator getInstance() {
    return instance;
  }
  public long getId() { 
    return id.incrementAndGet();
  }
}
2.懒汉式

​ 支持延迟加载。但给 getInstance() 这个方法加了一把大锁(synchronzed),导致这个函数的并发度很低。

public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private static IdGenerator instance;
  private IdGenerator() {}
  public static synchronized IdGenerator getInstance() {
    if (instance == null) {
      instance = new IdGenerator();
    }
    return instance;
  }
  public long getId() { 
    return id.incrementAndGet();
  }
}
3.双重检测

​ 既支持延迟加载、又支持高并发的单例实现方式。

​ 只要 instance 被创建之后,即便再调用 getInstance() 函数也不会再进入到加锁逻辑中了。

public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private static IdGenerator instance;
  private IdGenerator() {}
  public static IdGenerator getInstance() {
    if (instance == null) {
      synchronized(IdGenerator.class) { // 此处为类级别的锁
        if (instance == null) {
          instance = new IdGenerator();
        }
      }
    }
    return instance;
  }
  public long getId() { 
    return id.incrementAndGet();
  }
}

​ 因为指令重排序,可能会导致 IdGenerator 对象被 new 出来,并且赋值给 instance 之后,还没来得及初始化(执行构造函数中的代码逻辑),就被另一个线程使用了。要解决这个问题,我们需要给 instance 成员变量加上 volatile 关键字,禁止指令重排序才行。实际上,只有很低版本的 Java 才会有这个问题。我们现在用的高版本的 Java 已经在 JDK 内部实现中解决了这个问题(解决的方法很简单,只要把对象 new 操作和初始化操作设计为原子操作,就自然能禁止重排序)。

4.静态内部类
public class IdGenerator { 
  private AtomicLong id = new AtomicLong(0);
  private IdGenerator() {}

  private static class SingletonHolder{
    private static final IdGenerator instance = new IdGenerator();
  }
  
  public static IdGenerator getInstance() {
    return SingletonHolder.instance;
  }
 
  public long getId() { 
    return id.incrementAndGet();
  }
}

​ SingletonHolder 是一个静态内部类,当外部类 IdGenerator 被加载的时候,并不会创建 SingletonHolder 实例对象。只有当调用 getInstance() 方法时,SingletonHolder 才会被加载,这个时候才会创建 instance。instance 的唯一性、创建过程的线程安全性,都由 JVM 来保证。所以,这种实现方法既保证了线程安全,又能做到延迟加载。

5.枚举

​ 通过 Java 枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。

public enum IdGenerator {
  INSTANCE;
  private AtomicLong id = new AtomicLong(0);
 
  public long getId() { 
    return id.incrementAndGet();
  }
}

作者:captain_p
链接:https://juejin.cn/post/7040651819193729061
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:IdGenerator,private,instance,了解,模式,单例,new,public
From: https://www.cnblogs.com/bmmxz/p/16625408.html

相关文章

  • python selenium使用无头模式执行用例
    什么是无头模式?HeadlessBrowser模式是浏览器的无界面状态,即在不打开浏览器界面的情况下使用浏览器。该模式的好处如下:1)可以加快web自动化测试的执行时间,对于web自动化......
  • 你真的了解java的泛型吗?
    1.java可以声明泛型数组吗?​ 我们都知道在java中声明一个普通数组,但是你知道如何声明一个泛型数组吗?​ 先来看一个简单的例子,Animals是Cat的父类,思考下Animals[]和Cat[......
  • Unity-单例模板
    普通单例模板publicabstractclassSingleton<T>whereT:new(){privatestaticTinstance;publicstaticTInstance{get{if(i......
  • 生活中有哪些必备的知识技能需要了解? 黄海
    如何更好地处理拖延症的方法。利用帕金森定律来管理你的时间留给你的时间越多,你做一样事情就会倾向于慢慢完成。这就是为什么当你只剩下最后5分钟的时候,你的工作效率......
  • 架构、框架、设计模式的定义和区别
    一、架构架构即软件架构,是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。软件体系结构是构建计算机软件实践的基础,简单来说,软件架构是一个系......
  • Javascript:设计模式-简单工厂模式
    工厂模式大体分为三类:简单工厂模式、工厂方法模式、抽象工厂模式。在我们日常的实现功能逻辑中,最基础的一种方法是这样的:有一个体育器材店,每一种类型的运动器材都有名称......
  • Javascript:设计模式-代理模式
    例:该例为书中原例,小明(xiaoming)遇到了女神(A),打算送个花来告白,刚好小明打听到女神有个朋友叫(B),自己不太好意思,所以决定让B来送花,虽然这件事儿肯定是凉了,但是作为例子还是很......
  • 【FAQ】鸿蒙系统开启深色模式包含的应用是如何判断的?
    ​【问题描述】鸿蒙系统开启深色模式包含的应用是如何判断的?安卓应用适配了深色模式,但是筛选中不含有三方应用​【解决方案】根据与相关团队确认,支持深色模式的三方App......
  • 对象模式
    工厂模式构造函数就是普通函数,只不过首字母要大写,内部写this,环境指向被实例化的对象实例化:把某个变量,通过new构造函数变成了一个对象数组,字符串等都是构造函数原型......
  • 彻底了解线程池的原理——40行从零开始自己写线程池
    前言在我们的日常的编程当中,并发是始终离不开的主题,而在并发多线程当中,线程池又是一个不可规避的问题。多线程可以提高我们并发程序的效率,可以让我们不去频繁的申请和释放......