首页 > 其他分享 >头一次见单例模式讲的如此透彻

头一次见单例模式讲的如此透彻

时间:2023-06-23 11:55:07浏览次数:38  
标签:Singleton 对象 模式 instance 实例 透彻 单例 加载

简介

单例模式是一种常用的软件设计模式,用于创建类型。通过单例模式的方法创建的类在当前进程中只有一个实例。单例模式的类只能允许一个实例存在。单例模式的作用是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个。

组成部分:

  1. 私有化构造方法。
  2. 私有化内部实例。
  3. 公有静态方法用来获取内部实例。

单例模式

优缺点

单例模式的优点有:

  • 提供了对唯一实例的受控访问,可以保证对象的唯一性和一致性。
  • 减少了内存开销,避免了频繁的创建和销毁对象。
  • 避免了对资源的多重占用,例如文件操作、数据库连接等。

单例模式的缺点有:

  • 不支持继承和多态,违反了单一职责原则,一个类应该只关心内部逻辑,而不关心外部如何实例化。
  • 不易扩展,如果需要创建多个实例,就需要修改代码,违反了开闭原则,一个类应该对扩展开放,对修改关闭。
  • 不支持有参数的构造函数,如果需要传递参数,就需要修改方法或者定义其他方法。
  • 可能存在反射或者反序列化攻击,破坏单例的唯一性。

应用场景

单例模式适用于以下场景:

  • 需要频繁创建和销毁的对象,例如缓存、线程池、注册表等。
  • 需要控制资源的访问,例如文件操作、数据库连接等。
  • 需要保证对象的唯一性和一致性,例如配置信息、全局变量等。

Java 代码示例

在 Java 中,有五种不同的单例实现方法。其中包括饿汉式、懒汉式、双检锁、静态内部类和枚举类。
单例模式的五种实现原理分别是饿汉式、懒汉式、双重检测、静态内部类和枚举类。它们各自的优缺点如下:

  • 饿汉式:原理是在类加载的时候,就创建并初始化一个静态的实例对象,然后通过一个静态的方法返回这个实例。优点是线程安全,不需要加锁;缺点是不支持延迟加载,可能会浪费资源。
public class Singleton {
    private Singleton() {}
    private static Singleton instance;
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
  • 懒汉式:原理是在第一次调用获取实例的方法时,才创建并初始化一个静态的实例对象,然后返回这个实例。为了保证线程安全,需要给获取实例的方法加上synchronized关键字。优点是支持延迟加载,节省资源;缺点是线程不安全,需要加锁,影响性能。
public class Singleton {
    private Singleton() {}
    private static final Singleton instance = new Singleton();
    public static Singleton getInstance() {
        return instance;
    }
}
  • 双重检测:原理是在第一次调用获取实例的方法时,先判断静态的实例对象是否为空,如果为空,则进入同步代码块,再判断一次是否为空,如果为空,则创建并初始化一个静态的实例对象,然后返回这个实例。为了防止指令重排序导致空指针异常,需要给静态的实例对象加上volatile关键字。优点是线程安全,支持延迟加载,不需要加锁;缺点是可能会出现空指针异常,需要使用 volatile 关键字防止指令重排序。
public class Singleton {
    private Singleton() {}
    private static volatile Singleton instance;
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  • 静态内部类:原理是利用了 Java 静态内部类的特性,即外部类加载时不会加载内部类,只有在使用到内部类时才会加载。因此,在第一次调用获取实例的方法时,才会加载静态内部类,并创建并初始化一个静态的实例对象,然后返回这个实例。优点是线程安全,支持延迟加载,不需要加锁;缺点是不能防止反射或者反序列化攻击。
public class Singleton {
    private Singleton() {}
    private static class Instance {
        private static final Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return Instance.instance;
    }
}
  • 枚举类:原理是利用了Java枚举类型本身的特性,即枚举类型在加载时就会创建所有的枚举常量,并且保证了线程安全性和唯一性。因此,在调用获取实例的方法时,直接返回枚举常量即可。优点是线程安全,简单易用,可以防止反射或者反序列化攻击;缺点是不支持延迟加载,不能继承其他类。
public enum Singleton {
     INSTANCE;
}

这些不同的实现方式有不同的适用场景,需要根据具体的需求和条件来选择。在这里,我只能给出一些个人的看法,仅供参考。

  • 如果对内存资源比较敏感,或者单例对象不需要频繁使用,可以考虑使用懒汉式或者双重检测,因为它们支持延迟加载,可以节省资源。
  • 如果对性能比较敏感,或者单例对象需要频繁使用,可以考虑使用饿汉式或者静态内部类,因为它们不需要加锁,可以提高效率。
  • 如果对安全性比较敏感,或者需要防止反射或者反序列化攻击,可以考虑使用枚举类,因为它可以保证实例的唯一性和不可变性。
  • 如果对简洁性比较敏感,或者不需要继承其他类,可以考虑使用枚举类,因为它是最简单的实现方式。

个人来说在编码效率和可维护性上我比较倾向于使用静态内部类的实现方式,既能保证线程安全性,又能支持延迟加载。

Spring 代码示例

在 Spring 框架中,Spring 默认使用单例模式来创建和管理 Bean 对象,但是可以通过 @Scope("singleton") 注解来指定 Bean 对象的作用域。

  • @Scope("singleton"):表示该Bean对象是一个单例对象,在整个Spring容器中只有一个实例。
  • @Scope("prototype"):表示该Bean对象是一个原型对象,在每次请求时都会创建一个新的实例。
  • @Scope("request"):表示该Bean对象的作用域是一个HTTP请求,在同一个请求中只有一个实例。
  • @Scope("session"):表示该Bean对象的作用域是一个HTTP会话,在同一个会话中只有一个实例。

总结

单例模式是一种简单而常用的设计模式,它可以保证一个类只有一个实例,并提供一个全局访问点。单例模式有多种实现方式,各有优缺点。单例模式可以节约系统资源,避免资源冲突,保证对象的唯一性和一致性。但是单例模式也有不利于继承和扩展的缺点,以及可能存在的安全隐患。在使用单例模式时,需要根据具体情况和需求选择合适的方法,并注意避免潜在的问题。

关注公众号【waynblog】每周分享技术干货、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力!

标签:Singleton,对象,模式,instance,实例,透彻,单例,加载
From: https://www.cnblogs.com/waynaqua/p/17498933.html

相关文章

  • 装饰模式-11
    概述装饰模式(DecoratorPattern)又称包装器,与适配器模式别名一样,但使用的目的不同。它动态地给一个对象添加职责,相比于通过继承添加职责更加灵活。也称“油漆工”模式(视翻译而定)。优点:扩展对象功能的同时提高了灵活性,符合“开闭原则”。缺点:增加系统的复杂性。interfaceCo......
  • Android四种Activity的加载模式
    建议首先阅读下面两篇文章,这样才可以更好的理解Activity的加载模式:Android的进程,线程模型其中对“Android的单线程模型”的描述,明白Activity的一些注意事项。AndroidApplicationTaskActivities的关系尤其要明白Task是啥。 一个Activty的生命周期Activty的生命周期的也......
  • RAW域算法之固定模式噪声消除FPN
    固定模式噪声消除(FixedPatternNoiseRemove)由于Sensor工艺的原因导致了Sensor会在固定的位置产生相对固定的随时间变化较小的噪声,称之为固定模式噪声。固定模式噪声一般出现于CMOSSensor,并且Sensor的模拟增益或者列增益开的越大,固定模式噪声越明显。图12增益增大时......
  • hiredis的同步模式和异步模式
    1.什么是hiredisHiredis是一个C语言编写的Redis客户端库,用于与Redis数据库进行交互。它提供了一个简洁而高效的接口,使开发人员可以方便地在自己的C/C++项目中使用Redis。Hiredis是一个开源项目,可从其官方GitHub仓库获取源代码,并在符合BSD许可证的条件下使用和分......
  • 智能化制造:一种新的生产模式
    目录1.引言2.技术原理及概念3.实现步骤与流程4.应用示例与代码实现讲解5.优化与改进6.结论与展望智能化制造:一种新的生产模式随着人工智能技术的不断发展,智能化制造成为了现代制造业的一个重要趋势。智能化制造能够实现生产过程中的自动化、智能化和数据化,提高生产效率和......
  • 20230430 28. 访问者模式 - 男女对比
    介绍访问者模式(Visitor),表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作访问者模式适用于数据结构相对稳定的系统访问者模式把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。......
  • 20230427 23. 命令模式 - 烧烤点单
    介绍命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作Command类,用来声明执行操作的接口ConcreteCommand类,将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现executeCommandInvoker......
  • 20230428 24. 职责链模式 - 审批流程
    介绍职责链模式(ChainofResponsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。Handler类,定义一个处理请示的接口ConcreteHandler类,具体处理者类,处理它所负责的请......
  • 20230430 26. 享元模式 - 网站复用
    介绍享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。在享元对象内部并且不会随环境改变而改变的共享部分,可以称为是享元对象的内部状态,而随环境改变而改变的、不可以共享的状态就是外部状态了。事实上,享元模式可以避免大量非常相似类的开销。在程序设计中,有时需......
  • 20230430 27. 解释器模式 - 音符
    解释器模式(interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器......