第一个设计模式——单例模式

news2024/11/17 1:47:40

目录

一、特点:

二、实现单例模式步骤

三、饿汉式

四、懒汉式

五、双重检查锁

六、静态内部类

七、枚举

八、可能被反序列化和反射破坏什么意思?

九、如何解决呢?


一、特点:

  1. 唯一性,单例模式确保程序中只有一个实例存在
  2. 节省内存开销,不用多次创建对象

二、实现单例模式步骤

  1. 私有化构造函数,防止外部实例化
  2. 提供公共获取单例对象的静态方法

三、饿汉式

饿汉式是什么?

        指在类加载时就完成了初始化。

  • java实现
public class Singleton {
    //创建一个静态的单例对象
    private static final Singleton instance = new Singleton();

    //私有化构造函数,防止外部实例化
    private Singleton(){}

    //提供公共的获取单例对象的静态方法
    public static Singleton getInstance(){
        return instance;
    }

}
  • kotlin实现  
object Singleton {
    //Kotlin的object关键字自动实现了饿汉式单例
}
  

优点:是线程安全的,因为JVM在进行类加载的时候,会进行加锁,每个类只有一份class对象,然后类加载的时候就会执行静态代码块、静态变量。

缺点:可能被反序列化和反射破坏、浪费资源,当你不需要单例实例,只想调用类中的静态方法时,它都会帮你执行静态代码块和静态变量,因为类加载。例如:


四、懒汉式

懒汉式是什么?

        是指第一次调用时才初始化

        1.不正确的懒汉式单例模式:

        虽然最后打印的结果是一样的对象,这是只有主线程的情况,但是如果在多线程下呢?

java例子:

koltin例子:

        可以看到如果在多线程下,该对象就会被创建多次,所以这种方法是不对的。

        2.正确的懒汉式单例模式:

  • java实现
public class Singleton {
    //创建一个静态的单例对象
    private static Singleton instance = null;

    //私有化构造函数,防止外部实例化
    private Singleton(){
        System.out.println("Singleton正在实例化");
    }

    //提供公共的获取单例对象的静态方法
    public synchronized static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }

}
  • kotlin 实现
class Singleton {
    private constructor(){
        println("Singleton正在被实例")
    }

    companion object{
        private var instance:Singleton? = null

        @Synchronized
        public fun  getInstance():Singleton{
            if(instance == null){
                instance = Singleton()
            }
            return instance!!
        }
    }

}

优点:在多线程下,能保证该类只实例一次。

缺点:可能被反序列化和反射破坏、为方法加锁,粒度太大,即锁定的范围过宽。这意味着锁保护的区域较大,包括了多个操作或整个方法,这会对系统的性能和并发能力产生一些负面影响,多个线程可能因为需要访问一个被锁定的方法而排队等待,导致线程资源的低效使用。

进行优化,减小锁的范围:


五、双重检查锁

  • java实现
public class Singleton {
    //创建一个静态的单例对象
    private volatile static Singleton instance = null;

    //私有化构造函数,防止外部实例化
    private Singleton(){
        System.out.println("Singleton正在实例化");
    }

    //提供公共的获取单例对象的静态方法
    public  static Singleton getInstance(){
        if(instance == null){
            synchronized(Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  • kotlin实现
class Singleton {
    private constructor(){
        println("Singleton正在被实例")
    }

    companion object{
        @Volatile
        private  var instance:Singleton? = null


        public fun  getInstance():Singleton{
            if(instance == null){
                synchronized(Singleton::class.java) {
                    if(instance == null) {
                        instance = Singleton()
                    }
                }
            }
            return instance!!
        }
    }
}

优点:线程安全、提高了性能、避免了资源浪费。

缺点:可能被反序列化和反射破坏、结构复杂,要记得加volatile关键字。


六、静态内部类

  • java实现
public class Singleton {

    //私有化构造函数,防止外部实例化
    private Singleton(){
        System.out.println("Singleton正在实例化");
    }

    // 静态内部类,只有在第一次被访问时才会被加载
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    
}
  • kotlin实现
class Singleton {
    private constructor(){
        println("Singleton正在被实例")
    }

    companion object{
        object SingletonHolder{
            val INSTANCE = Singleton()
        }
        
        public fun getInstance():Singleton{
            return SingletonHolder.INSTANCE
        }
    }
}

优点:线程安全、避免了资源浪费、实现简单

 缺点:可能被反序列化和反射破坏、它的线程安全是依靠类加载,但是类加载是耗性能的,类加载的过程:


七、枚举

  • java实现
public enum Singleton {
    INSTANCE;
    
    // 可以在这里添加其他方法和属性
}
  • kotlin实现
enum class Singleton {
    INSTANCE;
    
    // 可以在这里添加其他方法和属性
}

优点:代码写法简洁优雅、线程安全(通过反编译class文件,可以看到INSTANCE是一个静态变量。那么就是通过类加载来保证线程安全的)、可以防止反序列化和反射破坏单例、并且不用手动私有化构造函数。

缺点:不能继承其它类,因为它内部已经继承了Enum类、它的线程安全是依靠类加载,但是类加载是耗性能的。


八、可能被反序列化和反射破坏什么意思?

        1.反序列化破坏:将一个单例对象进行序列化后,再反序列化,而反序列化的对象和程序对象不是同一个对象。除了枚举的单例,其它的方式都会被反序列化破坏。

        例如,以饿汉式为例子:

        2.反射破坏:通过反射调用类的无参构造函数进行创建出来对象和程序的单例对象不是同一个对象。除了枚举的单例,其它的方式都会被反射破坏

        例如,以饿汉式为例子:

        3.看看枚举的例子:

        反射创建对象,直接报错:

        序列化和反序列化不会破坏对象:


九、如何解决呢?

  • 对于序列化破坏:

  • 对于反射破坏:        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1956210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

甘肃粉条:一口爽滑,满心欢喜

在甘肃的美食世界里,粉条是一道独具特色的存在,它以其爽滑的口感和多样的烹饪方式,赢得了无数人的喜爱。甘肃食家巷粉条,选用当地优质的土豆或红薯为原料,经过一系列精细的加工工艺,最终成就了这一根根晶莹…

SSRF (服务端请求伪造)

🎼个人主页:金灰 😎作者简介:一名简单的大一学生;易编橙终身成长社群的嘉宾.✨ 专注网络空间安全服务,期待与您的交流分享~ 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️ 🍊易编橙终身成长社群&#…

2-48 基于matlab的EM算法聚类可视化程序

基于matlab的EM算法聚类可视化程序,通过期望最大化算法(EM)优化类别间距,使得类别间距最大、类内间距最小。输出聚类前后结果及收敛曲线。程序已调通,可直接运行。 2-48 期望最大化算法(EM) 聚类…

6/9-axis imu sensor/姿态传感器 学习板/开发板 开源 MPU6500 QMC5883 加速度 陀螺仪 地磁传感器

1-应用领域: 游戏交互、3D模型控制、机器人、设备姿态检测、翻转状态检测、无人机、无人船、无人车、VR/AR、AHRS、姿态算法研究与分析,短距无效姿态测量、车辆调平系统,机器震动检测 2-产品硬件规格: 尺寸: 蓝牙:5.0 电池:默认150ma&…

TCP程序设计

TCP概述 建立连接 客户端和服务器端在建立连接时: 服务端是典型的监听接受连接的模式,就是ListenAccept 客户端是主动建立连接的模式,就是Dial Go语言中使用 net包实现网络的相关操作,包括我们TCP的操作。 用于建立连接的典型…

tusiart吐司艺术图像生成、LoRA 模型的使用和训练网站

文章目录 前言一、Tusiart(吐司艺术)是什么二、Tusiart(吐司艺术)主要功能三、Tusiart(吐司艺术) 网站图片四、Tusiart(吐司艺术) 相关地址总结 前言 每天分享一个关于AI项目或者网…

【系统架构设计师】二十、云原生架构设计理论与实践①

目录 一、云原生架构内涵 二、云原生的原则 三、主要架构模式 四、典型的云原生架构反模式 相关推荐 一、云原生架构内涵 云原生架构是基于云原生技术的一组架构原则和设计模式的集合,旨在将云应用中的非业务代码部分进行最大化的剥离,从而让云设施…

SQL Server索引碎片的基本知识(附Demo)

目录 前言1. 基本知识2. 检索碎片2.1 dm_db_index_physical_stats2.2 DBCC SHOWCONTIG 3. 修复和优化 前言 索引碎片太高本身会阻碍查询的效率,这个问题要重视 1. 基本知识 索引中的数据页不再连续,导致存储和检索数据时的效率降低 碎片通常发生在以…

虚拟机启动电脑蓝屏问题解决方案

1.查看CPU虚拟化是否开启,没有开启的可以按照教程开启 打开任务管理器,查看是否开启CUP虚拟化 如果没有开启,可以查看下面的链接,进入BIOS开启 win10如何开启虚拟化支持_win10开启cpu虚拟化的方法-系统城 2,控制面板…

C#中的同步编程和异步编程

1. 简单描述一下同步编程和异步编程 同步编程:按照代码的顺序一行一行执行,如果某个操作需要等待(比如读取文件、网络请求、数据库操作等),那么当前的线程就会停下来,一直到这个操作完成了之后&#xff0c…

无坚不摧的Python重试机制:探索Tenacity库

无坚不摧的Python重试机制:探索Tenacity 库 背景:为何选择Tenacity? 在软件开发中,我们经常面临需要重试操作的场景,比如网络请求、数据库操作等。这些操作可能会因为各种原因暂时失败,但稍后可能会成功…

更换CentOS Stream 8镜像源

CentOS Stream 8替换阿里云镜像源 确认CentOS版本 hostnamectl备份当前配置 sudo cp -r /etc/yum.repos.d /etc/yum.repos.d.backup创建临时文件下载目录 mkdir -p /tmp/aliyun-repos cd /tmp/aliyun-repos下载 .repo 文件列表并解析链接 wget -r -np -nd -A ".repo&…

ssm框架整合,异常处理器和拦截器(纯注解开发)

目录 ssm框架整合 第一步:指定打包方式和导入所需要的依赖 打包方法:war springMVC所需依赖 解析json依赖 mybatis依赖 数据库驱动依赖 druid数据源依赖 junit依赖 第二步:导入tomcat插件 第三步:编写配置类 SpringCon…

C++知识点总结:2.类和对象(自用)

类和对象 1. 类和对象的关系2. 对象指针3. 在堆上创建对象4. 成员访问限定符5. 名字编码(Name Mangling)6.构造函数7.构造函数的重载8.初始化列表8. 成员变量初始化的顺序(通过初始化列表)9. 初始化 const 成员变量10. 析构函数11…

安装 moleculeSTM 踩坑日记

“学习 LLM ,在大模型时代为自己存张船票”。 相信很多人都有这样的想法。那么,在 AI for science 领域,哪些 LLM 模型值得一试呢? 笔者认为: LLM 直接预测 SMILES 性质 or 直接生成 SMILES 的技术路线是行不通的。因…

成为git砖家(6): git restore 命令

文章目录 1. git restore 命令是新命令2. git官方对于restore命令的说明3. 总结 1. git restore 命令是新命令 在2019年8月发布的 Git 2.23 版本中,git checkout 命令的功能被拆解到两个新的命令中: git switch: 负责分支相关的操作git restore: 负责文…

微信小程序教程001:小程序简介

文章目录 学习目标小程序简介1、小程序和普通网页开发的区别2、注册小程序账号3、获取小程序的AppID4、安装开发者工具4.1 了解开发者工具4.2 下载开发工具 5、设置开发者工具外观 学习目标 如何创建小程序项目小程序项目的基本组成结构小程序页面由几部分组成小程序常见的组件…

Vscode——如何快速搜索项目工程中的某个文件的位置

第一步:按 shift ctrl p 第二步:然后把 > 删除 第三步:输入文件名称即可

Linux环境docker部署Firefox结合内网穿透远程使用浏览器测试

文章目录 前言1. 部署Firefox2. 本地访问Firefox3. Linux安装Cpolar4. 配置Firefox公网地址5. 远程访问Firefox6. 固定Firefox公网地址7. 固定地址访问Firefox 前言 本次实践部署环境为本地Linux环境,使用Docker部署Firefox浏览器后,并结合cpolar内网穿…