当前位置: 首页 > article >正文

Javaee:单例模式

文章目录

  • 单例模式
  • 单例模式的使用场景
  • 单例模式的实现方式
    • 饿汉模式(急)
      • 实现方式
    • 懒汉模式(缓)
      • 使用静态内部类创建单例模式(推荐)
  • 总结

单例模式

保证一个类只能创建一个实例,不能创建多个实例

单例模式的使用场景

如果频繁的创建和销毁对象的开销非常大,并且这些类的对象可以复用,势必会造成资源浪费,性能低和资源利用率低

举例:数据库连接池
访问数据库,需要创建数据库链接对象,创建数据库链接对象和销毁的开销是非常大的,而数据库连接池会采用单例模式,只实例一个对象来确保连接池的唯一性和全局可访问性,也就很好的提高资源利用率

好处

  1. 通过重用连接池中的连接,避免了频繁地创建和销毁数据库连接,从而节省了系统资源。
  2. 可以更容易地管理和监控连接池的状态和性能。

线程池中也应用了单例模式的设计模式

单例模式的实现方式

饿汉模式(急)

在类加载的同时创建实例

实现方式

class Singlation{
    private static Singlation instance=new Singlation();

    public static Singlation getInstance() {
        return instance;
    }
    private Singlation(){}

}

由于在类加载的过程就创建了实例,不涉及线程安全问题

重点:

  1. 使用private修饰构造方法——不能通过new直接创建对象
  2. 使用static修饰对象——类加载就创建好对象
  3. 通过调用getInstance——获得实例对象

优点

类加载就创建实例,只涉及到读操作,天生线程安全
没有加锁,可以直接使用,减少延迟

缺点

无论是否需要使用都会在类加载时创建,可能会导致资源浪费
若是重启服务,无法实现延迟加载的特性,会拖慢运行速度

懒汉模式(缓)

只有在真正需要时才创建实例

单线程版本

class SingletionLazy {
    private static SingletionLazy instance = null;
    public static SingletionLazy getInstance() {
        if (instance == null) {
        	instance = new SingletionLazy()       
        }
        return instance;
    }
}

只有在真正需要时才创建实例——懒

举例:

妈妈叫我去小卖部买酱油,而我在看电视,此时我的做法是不听妈妈的话,继续看电视,等到妈妈要生气了我才去买

不难发现上述代码是线程不安全的,在多个线程下,很有可能会越过判断语句,直接去创建对象

改进

class SingletionLazy {
    private static SingletionLazy instance = null;
    public static SingletionLazy getInstance() {
            synchronized (locker) {
                if (instance == null) {
                    instance = new SingletionLazy();
                }
            } 
        return instance;
    }
}

加锁,在构建对象的时候才需要考虑同步,所以我们对于new对象的操作进行加锁,上述代码中getInstance是读操作,不存在锁竞争,所有线程都能访问,而第二步的判断,如果没有实例创建,所有的线程就会去竞争锁,抢到锁的线程创建好实例,以后的getInstance操作都是直接返回当前实例对象。

但是有个问题,如果同时有两个线程进入了if语句,其中一个线程拿到锁创建实例之后将锁释放了,此时另一个线程也能创建实例——不符合要求,线程不安全

解决方案:双重检锁

使用if语句检查当前实例是否已经被创建

还要注意内存可见性问题

instance = new SingletionLazy();	

对应三条指令

  1. 给对象分配内存
  2. 初始化对象
  3. 返回对象指向的内存地址

编译器在逻辑不改变的情况会自动优化,进行指令重排序

解决方案:volatile关键字

优化版本

class SingletionLazy {
    private static volatile SingletionLazy instance = null;
    private static Object locker = new Object();

    public static SingletionLazy getInstance() {
        if (instance == null) {//判断实例是否已经创建
            synchronized (locker) {
                if (instance == null) {//判断是否需要new对象
                    instance = new SingletionLazy();
                }
            }
        }
        return instance;
    }
}

优点

真正需要创建实例的时候,先判断是否为空,如果为空,再创建单例对象
真正需要用到的时候创建减少了不必要的开销

使用静态内部类创建单例模式(推荐)

这种方式是线程安全的,不需要额外的同步(不用加锁)

public class Singleton {  
  
    // 私有构造函数  
    private Singleton() {  
        // 初始化代码  
    }  
    // 静态内部类,负责持有单例实例  
    private static class SingletonHelper {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
 
    // 获取单例实例的公共静态方法  
    public static Singleton getInstance() {  
        return SingletonHelper.INSTANCE;  
    }  
    public static void main(String[] args) {  
        Singleton singleton = Singleton.getInstance();    
    }  
}

总结

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。有多种实现方式,懒汉模式需要注意线程安全问题。


http://www.kler.cn/a/371513.html

相关文章:

  • HttpServer模块 --- 封装TcpServer支持Http协议
  • Junit5中用Excel进行数据驱动
  • 模具生产管理系统软件:提升制造业效率的新利器
  • GPT避坑指南:如何辨别逆向、AZ、OpenAI官转
  • NAT技术和代理服务器
  • STM32主从定时器输出个数、频率可调的脉冲
  • ubuntu配置xrdp
  • Robotaxi砍掉的特斯拉市值,财报又赢回来了
  • 在 Node.js 中使用 .env 文件
  • final关键字
  • Azure 将文本转换为语音
  • this指针使用演示(C++)
  • Jetson AGX Orin 实现相机雷达联合标定
  • 用sdcc给51单片机编译C程序
  • 绿色制造中的 FMEA 系统的应用_SunFMEA软件
  • iOS Swift5算法恢复——HMAC
  • 『大模型笔记』如何在无网路的情况下在Linux主机上安装NVIDIA Container Toolkit(nvidia-docker2)
  • Nginx、Lua 和 Redis 架构来实现 IP 黑名单
  • 大话网络协议:HTTPS协议和HTTP协议有何不同?为什么HTTPS更安全
  • 014 安装DHCP服务器
  • Halcon相机外参自理解
  • Golang的多版本管理
  • VScode编译C++的配置文件
  • 今日总结10.29
  • 【Mac】Homebrew
  • Soanrquber集成Gitlab 之 gitlab用户配置和身份验证