单例设计模式

一、单例模式定义

确保某一个类只有一个实例,且能自行实例化并向整个系统提供这个实例。

1. 使用场景

  1. 数据库连接池:在一个应用中,通常需要频繁地连接数据库,如果每个模块都创建一个数据库连接对象,会造成资源浪费和不一致的问题。使用单例模式可以保证整个应用中只有一个数据库连接池对象,避免了这个问题。

  2. 线程池:在一个应用中,通常需要创建大量的线程来处理任务,如果每个任务都创建一个新的线程,会造成系统资源浪费和不稳定的问题。使用单例模式可以保证整个应用中只有一个线程池对象,避免了这个问题。

  3. 缓存系统:在一个应用中,通常需要频繁地使用缓存来提高性能,如果每个模块都创建一个缓存对象,会造成资源浪费和不一致的问题。使用单例模式可以保证整个应用中只有一个缓存对象,避免了这个问题。

  4. 总之,单例模式适用于需要全局唯一、频繁使用的对象场景,可以避免资源浪费和不一致的问题,提高应用的性能和稳定性。

2. 代码实现(DCL)

这里以双重校验锁DCL(Double-Checked Locking)为例

//懒汉式单例类.在第一次调用的时候实例化自己 
public class Singleton {
    private Singleton() {}
    private volatile static Singleton singleton = null;
    
    public static Singleton getInstance() {
        if (singleton == null) {  
            synchronized (Singleton.class) {  
               if (singleton == null) {  
                  singleton = new Singleton(); 
               }  
            }  
        }  
        return singleton; 
    }
}

3. 扩展

3.1 为什么 getInstance() 方法内需要使用两个 if (singleton == null) 进行判断呢?

假设高并发下,线程A、B 都通过了第一个 if 条件。若A先抢到锁,new 了一个对象,释放锁,然后线程B再抢到锁,此时如果不做第二个 if 判断,B线程将会再 new 一个对象。使用两个 if 判断,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗。

3.2 volatile 关键字的作用?

首先 singleton = new Singleton() 这段代码其实不是原子性的操作,至少分为以下3个步骤:
  1. 给singleton对象分配内存空间
  2. 调用Singleton类的构造函数等,初始化singleton对象
  3. 将singleton对象指向分配的内存空间

这步一旦执行了,那singleton对象就不等于null了,这里还需要知道一点,就是有时候JVM会为了优化,需要做指令重排序的操作,这里的指令,指的是CPU层面的。正常情况下,singleton = new Singleton() 的步骤是按照 1->2->3 这种步骤进行的,但是一旦JVM做了指令重排序,那么顺序很可能编程 1->3->2,如果是这种顺序,可以发现,在3步骤执行完 singleton 对象就不等于 null,但是它其实还没做步骤二的初始化工作,但是另一个线程进来时发现,singleton不等于null了,就这样把半成品的实例返回去,调用是会报错的。

4. 小结

  • 单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点来访问该实例。

  • 单例模式的核心思想是通过限制类的实例化过程,确保在整个应用程序中只有一个实例对象存在。这种限制可以通过私有化类的构造函数来实现,使得外部无法直接实例化该类。

  • 单例模式有两种常见的实现方式:饿汉式和懒汉式。饿汉式是指在类加载时就创建一个实例对象,并在类的静态变量中保存该实例对象。懒汉式是指在第一次使用时才创建实例对象,并在类的静态方法中进行延迟初始化。

  • 使用单例模式可以确保系统中某个类只有一个实例,从而节省了系统资源,并提供了一个全局访问点,方便其他对象访问该实例。单例模式可以应用于需要共享资源的情况,例如数据库连接池、线程池等。

  • 然而,单例模式也有一些缺点。由于实例对象是全局唯一的,因此单例模式会增加代码的耦合性和复杂度。单例模式也可能面临并发访问的问题,需要在实现中考虑线程安全性。

  • 总结来说,单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点来访问该实例。它可以节省系统资源并提供方便的访问方式,但也需要考虑代码的复杂性和线程安全性。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Run,boy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值