【设计模式】23种设计模式之单件/单例模式

本文详细介绍了单例模式的概念、UML类图、使用场景及优缺点。单例模式确保一个类只有一个实例,常用于内存压力降低、频繁创建对象的场景。文中分别讲解了懒汉式(线程安全的volatile实现)和饿汉式的实现方式,并强调了单例模式的扩展困难和并发测试挑战。最后,提醒了避免单例类继承和反射破坏单例的原则。

单件/单例模式

定义

单件模式确保一个类只有一个实例,并提供一个全局访问点。即该类对象在内存中只有一个。

例如:计算机系统中的任务管理器、还有 Windows 的回收站、操作系统中的文件系统、多线程中的线程池、显卡的驱动程序对象、打印机的后台处理服务、应用程序的日志对象、数据库的连接池、网站的计数器、Web 应用的配置对象、应用程序中的对话框、系统中的缓存等常常被设计成单件。

单件模式在现实生活中的应用也非常广泛,例如公司 CEO、部门经理等都属于单件模型。

单件模式两种类型:

​ 1.懒汉式:在真正需要使用到对象时才去创建单例类对象

​ 2.饿汉式,在类加载时就去创建单例类对象

UML类图

在这里插入图片描述

uniqueInstance:该成员变量持有唯一的Singleton实例

Singleton:私有构造器,保证其他地方不能通过new得到一个Singleton实例对象

getInstance:一个全局访问点。通过这个公共的静态方法可以得到唯一的Singleton实例

使用场景

1.需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少 Gtrea 5rfv5’ ]/ 5v5C

2.某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等

3.某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用

4.某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等

5.频繁访问数据库或文件的对象

6.对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套

7.当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等

示例

懒汉式
/**
 * 单件模式-懒汉式
 */
public class Singleton1 {

    private volatile static Singleton1 singleton1;
    // 其他成员变量

    // 私有构造器
    private Singleton1() {

    }

    /**
     * 双重检查加锁保证多线程下得到的实例唯一
     * @return 唯一实例
     */
    public static Singleton1 getInstance() {
        if (singleton1 == null) {
            synchronized (Singleton1.class) {
                if (singleton1 == null) {
                    singleton1 = new Singleton1();
                    return singleton1;
                }
            }
        }
        return singleton1;
    }

    // 其他成员方法
}

使用volatile关键字防止指令重排

创建一个对象,在JVM中会经过这三步:

​ 1.为singleton对象分配内存空间

​ 2.初始化singleton对象

​ 3.将singleton对象指向分配好的内存空间

所谓指令重排是指:JVM在保证最终结果正确的情况下,可以不按照程序编码的顺序指向语句,尽可能提高程序性能。因此,在1,2,3步中,可能发生指令重排现象,创建对象时顺序变为1-3-2,会导致多个线程获取对象时,有可能线程A创建对象过程中指向了1-3步骤,此时线程B判断singleton对象已经不为空,获取到还未初始化的singleton对象,就会报NPE异常。具体流程如下图:

在这里插入图片描述

饿汉式
/**
 * 单件模式-饿汉式
 */
public class Singleton2 {

    private static Singleton2 singleton2 = new Singleton2();
    // 其他成员变量

    // 私有构造器
    private Singleton2() {

    }

    // 获取唯一实例
    public static Singleton2 getInstance() {
        return singleton2;
    }

    // 其他成员变量
}

优缺点

优点:

1.单例模式可以保证内存里只有一个实例,减少了内存的开销

2.可以避免对资源的多重占用

3.单例模式设置全局访问点,可以优化和共享资源的访问

缺点:

1.单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则

2.在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象

3.单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则

注意

1.最好不要继承单件类。因为必须把单件的构造器改为public或protected,就不是真正的单件了

2.反射可以获取并改变单件类中的私有构造器,从而创建多个实例,破坏单件

总结

1.单件模式确保程序中,一个类最多只有一个实例

2.单件模式提供访问这个实例的全局全局点

3.在Java中实现单件模式需要私有构造器、一个静态变量、一个静态方法

4.确定在性能和资源上的限制,然后小心的选择适当的方案来实现单件,已解决多线程问题(设计时,我们必须认定所有的程序都是多线程的)

5.如果使用多个类加载器,可能导致单件失效从而产生多个实例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值