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

单例模式详细

文章目录

  • 单例模式
    • 介绍
    • 八种方式
    • 1、饿汉式(静态常量)
    • 2、饿汉式(静态代码块)
    • 3、懒汉式(线程不安全)
    • 4、懒汉式(线程安全,同步方法)
    • 5、懒汉式(线程不安全,同步代码块)
    • 6、双重检查
    • 7、静态内部类
    • 8、枚举
    • JDK 源码分析
    • 注意事项和细节说明
    • 小结

单例模式

介绍

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)

比如 Hibernate 的 SessionFactory,它充当数据存储源的代理,并负责创建 Session 对象。SessionFactory 并不是轻量级的,一般情况下,一个项目通常只需要一个 SessionFactory 就够,这是就会使用到单例模式

八种方式

  • 1)饿汉式(静态常量)
  • 2)饿汉式(静态代码块)
  • 3)懒汉式(线程不安全)
  • 4)懒汉式(线程安全,同步方法)
  • 5)懒汉式(线程安全,同步代码块)
  • 6)双重检查
  • 7)静态内部类
  • 8)枚举

1、饿汉式(静态常量)

  • 1)构造器私有化(防止外部 new)
  • 2)类的内部创建对象
  • 3)向外暴露一个静态的公共方法 getInstance
public class Singleton {// 1、构造器私有化private Singleton() {}// 2、类的内部创建对象private static final Singleton instance = new Singleton();// 3、向外暴露一个静态的公共方法public static Singleton getInstance() {return instance;}
}

优缺点

  • 1)优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题
  • 2)缺点:在类装载的时候就完成实例化,没有达到 Lazy Loading 的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费
  • 3)这种方式基于 classloder 机制避免了多线程的同步问题。不过,instance 在类装载时就实例化,在单例模式中大多数都是调用getlnstance 方法,但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 就没有达到 Lazy loading 的效果
  • 4)结论:这种单例模式可用,可能造成内存浪费

2、饿汉式(静态代码块)

  • 1)构造器私有化
  • 2)类的内部声明对象
  • 3)在静态代码块中创建对象
  • 4)向外暴露一个静态的公共方法
public class Singleton {// 1、构造器私有化private Singleton() {}// 2、类的内部声明对象private static Singleton instance;// 3、在静态代码块中创建对象static {instance = new Singleton();}// 4、向外暴露一个静态的公共方法public static Singleton getInstance() {return instance;}
}

优缺点

  • 1)这种方式和上面的方式其实类似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。优缺点和上面是一样的。
  • 2)结论:这种单例模式可用,但是可能造成内存浪费

3、懒汉式(线程不安全)

  • 1)构造器私有化
  • 2)类的内部创建对象
  • 3)向外暴露一个静态的公共方法,当使用到该方法时,才去创建 instance
// 1、构造器私有化
private Singleton() {
}// 2、类的内部声明对象
private static Singleton instance;// 3、向外暴露一个静态的公共方法,当使用到该方法时,才去创建 instance
public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;
}

优缺点

  • 1)起到了 Lazy Loading 的效果,但是只能在单线程下使用
  • 2)如果在多线程下,一个线程进入了判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例
  • 3)结论:在实际开发中,不要使用这种方式

4、懒汉式(线程安全,同步方法)

  • 1)构造器私有化
  • 2)类的内部创建对象
  • 3)向外暴露一个静态的公共方法,加入同步处理的代码,解决线程安全问题
public class Singleton {// 1、构造器私有化private Singleton() {}// 2、类的内部声明对象private static Singleton instance;// 3、向外暴露一个静态的公共方法,加入同步处理的代码,解决线程安全问题public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

优缺点

  • 1)解决了线程不安全问题
  • 2)效率太低了,每个线程在想获得类的实例时候,执行getlnstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低
  • 3)结论:在实际开发中,不推荐使用这种方式

5、懒汉式(线程不安全,同步代码块)

  • 1)构造器私有化
  • 2)类的内部创建对象
  • 3)向外暴露一个静态的公共方法,加入同步处理的代码块
public class Singleton {// 1、构造器私有化private Singleton() {}// 2、类的内部声明对象private static Singleton instance;// 3、向外暴露一个静态的公共方法,加入同步处理的代码,解决线程安全问题public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {instance = new Singleton();}}return instance;}
}

优缺点

  • 1)这种方式,本意是想对第四种实现方式的改进,因为前面同步方法效率太低,改为同步产生实例化的的代码块
  • 2)但是这种同步并不能起到线程同步的作用。跟第3种实现方式遇到的情形一致,假如一个线程进入了判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例
  • 3)结论:在实际开发中,不能使用这种方式

6、双重检查

  • 1)构造器私有化
  • 2)类的内部创建对象,同时用volatile关键字修饰修饰
  • 3)向外暴露一个静态的公共方法,加入同步处理的代码块,并进行双重判断,解决线程安全问题
public class Singleton {// 1、构造器私有化private Singleton() {}// 2、类的内部声明对象,同时用`volatile`关键字修饰修饰private static volatile Singleton instance;// 3、向外暴露一个静态的公共方法,加入同步处理的代码块,并进行双重判断,解决线程安全问题public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

优缺点

  • 1)Double-Check 概念是多线程开发中常使用到的,我们进行了两次检查,这样就可以保证线程安全了
  • 2)这样实例化代码只用执行一次,后面再次访问时直接 return 实例化对象,也避免的反复进行方法同步
  • 3)线程安全;延迟加载;效率较高
  • 4)结论:在实际开发中,推荐使用这种单例设计模式

7、静态内部类

  • 1)构造器私有化
  • 2)定义一个静态内部类,内部定义当前类的静态属性
  • 3)向外暴露一个静态的公共方法
public class Singleton {// 1、构造器私有化private Singleton() {}// 2、定义一个静态内部类,内部定义当前类的静态属性private static class SingletonInstance {private static final Singleton instance = new Singleton();}// 3、向外暴露一个静态的公共方法public static Singleton getInstance() {return SingletonInstance.instance;}
}

优缺点

  • 1)这种方式采用了类装载的机制,来保证初始化实例时只有一个线程
  • 2)静态内部类方式在 Singleton 类被装载时并不会立即实例化,而是在需要实例化时,调用getlnstance方法,才会装载Singletonlnstance 类,从而完成 Singleton 的实例化
  • 3)类的静态属性只会在第一次加载类的时候初始化,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的
  • 4)优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
  • 5)结论:推荐使用

8、枚举

public enum Singleton {INSTANCE;public void sayHello() {System.out.println("Hello World");}
}

优缺点

  • 1)这借助 JDK1.5 中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
  • 2)这种方式是 Effective Java 作者 Josh Bloch 提倡的方式
  • 3)结论:推荐使用

JDK 源码分析

JDK中 java.lang.Runtime 就是经典的单例模式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意事项和细节说明

  • 1)单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
  • 2)当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new
  • 3)单例模式使用的场景:需要频繁的进行创建和销毁的对象创建对象时耗时过多或耗费资源过多但又经常用到的对象(即:重量级对象)、工具类对象频繁访问数据库或文件的对象(比如数据源、session 工厂等)

小结

虽然上述提到的概念中,将双重检查、静态内部类、枚举三种方式的单例模式单独列举出来说明,但个人觉得本质也可以归类到饿汉式和懒汉式中;另外,同步代码块虽然上述中归类到线程安全,实际上并不是线程安全的

总结如下

  • |——饿汉式:静态常量、静态代码块、枚举(本质就是静态常量)
  • |——懒汉式
    • |——线程不安全:一次检查、同步代码块
    • |——线程安全:同步方法、双重检查、静态内部类
分类方式懒加载线程安全效率内存推荐指数(仅供参考)
饿汉式静态变量✔️✔️⭐️⭐️
~静态代码块✔️✔️⭐️⭐️
~枚举✔️✔️⭐️⭐️⭐️
懒汉式线程不安全✔️✔️✔️⭐️
~同步代码块✔️✔️✔️不要使用
~同步方法✔️✔️✔️⭐️
~双重检查✔️✔️✔️✔️⭐️⭐️⭐️
~静态内部类✔️✔️✔️✔️⭐️⭐️⭐️

相关文章:

单例模式详细

文章目录 单例模式介绍八种方式1、饿汉式(静态常量)2、饿汉式(静态代码块)3、懒汉式(线程不安全)4、懒汉式(线程安全,同步方法)5、懒汉式(线程不安全&#xf…...

Unity3D 自定义窗口

Unity3D 自定义窗口的实现。 自定义窗口 Unity3D 可以通过编写代码,扩展编辑器的菜单栏和窗口。 简单的功能可以直接一个菜单按钮实现,复杂的功能就需要绘制一个窗口展示更多的信息。 编辑器扩展的脚本,需要放在 Editor 文件夹中。 菜单栏…...

dubbo:dubbo整合nacos实现服务注册中心、配置中心(二)

文章目录 0. 引言1. nacos简介及安装2. 注册中心实现3. 配置中心实现4. 源码5. 总结 0. 引言 之前我们讲解的是dubbozookeeper体系来实现微服务框架,但相对zookeeper很多企业在使用nacos, 并且nacos和dubbo都是阿里出品,所以具备一些天生的契合性&#…...

个人博客指路

Pudding 个人博客 比较懒,直接 github page 了,没国内代理加速。 欢迎大佬们,踩一踩 没做留言,觉得很鸡肋。有问题可以在本文底下评论、或者直接邮件...

【STM32 HAL】多串口printf重定向

【STM32 HAL】多串口printf重定向 前言单串口printf重定向原理实现CubeMX配置Keil5配置 多串口printf重定向 前言 在近期项目中,作者需要 STM32 同时向上位机和手机发送数据,传统的 printf 重定向只能输出到一个串口。本文介绍如何实现 printf 同时输出…...

帆软报表,达梦数据库驱动上传失败

1、按照正常操作新建数据库连接,上传准备好的达梦驱动时,提示如图一需要修改SystemConfig.driverUpload为true才可以。 2、FineDB存储了数据决策系统中除平台属性配置以外的所有信息。详情请参见: FineDB 数据库简介。 3、因此管理员可通过…...

CSS选择器的优先级是如何确定的?有哪些方法可以提高选择器的效率?

CSS选择器的优先级是如何确定的? CSS选择器的优先级决定了当多个选择器同时应用于一个元素时,哪个选择器将最终生效。CSS选择器的优先级由多个因素决定,主要包括以下几个方面: 特殊性(Specificity) 特殊性…...

【MySQL】基础入门(第二篇)

1.MySQL基本数据类型 数值类型 MySQL 支持所有标准 SQL 数值数据类型。 这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC),以及近似数值数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。 关键字INT是INTEGER的同义词,关键字DEC是D…...

勇闯机器学习(第二关-数据集使用)

以下内容,皆为原创,重在无私分享高质量知识,制作实属不易,请点点关注。 好戏开场了~~~(这关涉及到了加载数据集的代码,下一关,教你们安装机器学习库) 一.数据集 这一关的目标 知道数据集被分为训练集和测…...

数据库学习(进阶)

数据库学习(进阶) Mysql结构:连接层:服务层(核心层):存储引擎层:系统文件层: 存储引擎(概述):存储引擎特点:InnoDB存储引擎:(为并发条…...

redis的数据结构——跳表(Skiplist)

跳表(Skiplist)是一种用于有序数据存储的高效数据结构,它在Redis中用于实现有序集合(Sorted Set,zset)的底层存储。当有序集合中的数据较多时,Redis会选择使用跳表来存储元素,以便在保持数据有序的同时提供高效的插入、删除、查找操作。 跳表的基本结构 跳表是一种多…...

Docker服务迁移

1 备份当前服务器上的 Docker 数据 1.1 停止 Docker 服务 为了确保数据一致性,在备份之前先停止 Docker 服务: sudo systemctl stop docker1.2 备份 Docker 数据 Docker 的数据通常位于 /var/lib/docker 目录。你可以使用 tar 命令将该目录压缩成一个…...

机器学习:逻辑回归实现下采样和过采样

1、概述 逻辑回归本身是一种分类算法,它并不涉及下采样或过采样操作。然而,在处理不平衡数据集时,这些技术经常被用来改善模型的性能。下采样和过采样是两种常用的处理不平衡数据集的方法。 2、下采样 1、概念 下采样是通过减少数量较多的类…...

React原理之Fiber双缓冲

前置文章: React原理之 React 整体架构解读React原理之整体渲染流程React原理之Fiber详解 -----读懂这一篇需要对 React 整体架构和渲染流程有大致的概念 😊----- 在前面的文章中,简单介绍了 Fiber 架构,也了解了 Fiber 节点的…...

机器学习笔记三-检测异常值

检测异常值是数据预处理中非常重要的一步,因为异常值可能会影响模型的训练效果,甚至导致错误的结论。以下是几种常见的检测异常值的方法: 1. 箱线图(Box Plot): 箱线图是一种简单的统计图形,可…...

如何评估Redis的性能

导语 Redis是一款高性能的内存数据库,被广泛用于缓存、持久化、消息队列等各种场景。为了确保Redis的高性能运行,评估Redis的性能是非常重要的。本文将介绍如何评估Redis的性能,并从问题解决的角度探讨如何优化Redis的性能。 1. 性能评估指…...

RabbitMQ发布订阅模式Publish/Subscribe详解

订阅模式Publish/Subscribe 基于API的方式1.使用AmqpAdmin定制消息发送组件2.消息发送者发送消息3.消息消费者接收消息 基于配置类的方式基于注解的方式总结 SpringBoot整合RabbitMQ中间件实现消息服务,主要围绕3个部分的工作进行展开:定制中间件、消息发…...

Android8.1源码下对APK进行系统签名

在Android8.1上面对APK进行Android系统源码环境下的签名,发现签名时出现如下错误: Exception in thread "main" java.lang.ExceptionInInitializerError at org.conscrypt.OpenSSLBIOInputStream.(OpenSSLBIOInputStream. at org.conscrypt.OpenSSLX509Certificat…...

2024年城市客运安全员考试题库及答案

一、单选题 376.根据《机动车运行安全技术条件》(GB7258---2017),每个应急出口应在其附近设有"应急出口"字样,字体高度应大于或等于()mm。 A.20 B.30 C.40 D.50 答案:C 377.根…...

全网最全面的Nginx内容(理论与实践相结合)

一、Web服​​务 1.1 web服务访问流程 1.2 Web服务 1.2.1 Web服务器分类 Web服务分为Apache和Nginx 1.2.2 Apache经典的Web服务器 1.2.2.1 Apache介绍 Apache HTTP Server(简称Apache)是Apache软件基金会的一个开放源码的网页服务器,可以…...

(七)Flink Watermark

Flink 的 Watermark 是用来标识数据流中的一个时间点。Watermark 的设计是为了解决乱序数据处理的问题,尤其是涉及到多个分区的 Kafka 消费者时。在 Watermark 的作用下,即使某些数据出现了延迟到达的情况,也不会导致整个处理流程的中断。此外,Watermark 还能防止过期的数据…...

springboot 上传文件失败:The temporary upload location

Caused by: java.io.IOException: The temporary upload location [/tmp/tomcat.379776875189163783.8081/work/Tomcat/localhost/jcys-core] is not valid 原因: Linux下会自动清除tmp目录下10天没有使用过的文件,SpringBoot启动的时候会在/tmp目录下生…...

UNiapp之微信小程序导出Excel

效果如下 参考小程序:日常记一记 ---账单页面 主要功能是根据筛选条件导出账单明细列表,实现该功能主要借助一个工具(excel.js),可在文章顶部下载或者一下网盘下载 https://pan.baidu.com/s/1RLisuG4_7FGD0Cnwewyabg?pwdpd2a 提取码: pd2a…...

fsadsadsad

adsadsafsada...

高效录制新选择:2024年Windows录屏软件

录屏能帮助我们捕捉屏幕上的精彩瞬间,作为老师可以用来录制课程,作为会议记录员可以用来录制远程会议。那么有什么软件是适合windows录屏的呢?这次我们一起来探讨一下吧。 1.福昕录屏大师 链接:www.foxitsoftware.cn/REC/ 这款软…...

Java技术面试(一面)

1、相面对象 1、面相对象语言/Java三大特性是什么? 引出 封装、‌继承和多态。 2、多态有哪些形式?多态使用过吗? 重载、重写,接口和抽象类的多个实现。考察工作经验、代码重构经验、习惯。 3、Java接口和抽象类有什么区别?你是如何选择使用的? 考察OOP的理解和工作…...

docker修改数据目录

新建docker数据目录 mkdir /data/docker-data停止docker服务 systemctl stop docker把docker数据迁移到新目录 cp -r /var/lib/docker/* /data/docker-data/修改docker配置 vi /etc/docker/daemon.json #添加data-root参数 {"data-root":"/data/docker-dat...

Appium学习

一、基础配置 import unittest from appium import webdriver from appium.options.android import UiAutomator2Options from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support …...

回顾 | 瑞云科技亮相ICIC2024,虚拟仿真实训云平台引关注

2024年8月7日,天津市虚拟仿真学会主办的第二十届智能计算国际会议(ICIC2024)——虚拟仿真技术交流平行会议暨天津市虚拟仿真学会2024年暑期技术交流会在天津盛大召开。本次大会汇聚来自全国的顶尖专家、学者和行业领袖,共同探讨虚…...

libLZMA库iOS18平台编译

1.下载xz源码: 使用autogen.sh生成configure文件 2.生成makefile rm -rf ./build/iOS && mkdir -p ./build/iOS && cd ./build/iOS && ../../configure --host=arm-apple-darwin64 --prefix=`pwd`/Frameworks/lzma CC="xcrun -sdk iphoneos cl…...

购物网站seo/百度关键词搜索量统计

1. 定义定义一个模板结构(框架,关键步骤,固定流程),将具体内容延迟到子类去实现,基于“继承”2. 应用场景1. 有多个子类共有的方法,且逻辑相同2. 重要的、复杂的方法,可以考虑作为模板方法3. 优缺点优点:提高代码复用性将相同部分…...

宁波seo教程app推广/seo快速排名多少钱

1、阿里云服务器 https://www.aliyun.com/ 2、百度云 https://bce.baidu.com/index.html 3、腾讯云 http://www.qcloud.com/ 4、360云 https://cloud.360.cn/ 5、ucloud https://www.ucloud.cn/ 6、美团云 https://mos.meituan.com/ 7、青云 https://www.qingcloud.com/ 云服务…...

建设一个班级网站的具体步骤/外链工厂

阅读使人充实,会谈使人敏捷,写作使人精确。——培根Linux 系统管理员试卷样题(中级)一、选择题:1、linux 操作系统内核创始人是( )A. Bill GatesB. Richard StallmanC. Linus TorvaldsD. Dennis M Ritchie 、Ken Thompson2、在linux 中有关I…...

wordpress顶部添加图片/长尾关键词排名系统

电商项目实战之商品秒杀定时任务corn表达式实现方式基于注解基于接口实战秒杀系统秒杀系统关注问题秒杀架构设计商品上架获取当前秒杀商品获取当前商品的秒杀信息秒杀最终处理参考链接定时任务 corn表达式 定时查询秒杀活动 https://cron.qqe2.com/ 实现方式 基于注解 内容…...

怎样做网站内链/宁德市人民医院

转:https://blog.csdn.net/u013673437/article/details/80534839 在编写MATLAB程序过程中,有时会遇到当程序运行到不满足if条件时让程序跳出,停止运行的情况,在MATLAB中,使用return语句实现程序跳出。 只将以上程序中变…...

昌平企业网站建设/百度的代理商有哪些

解决办法 在连接数据库时加上autocommitTrue db pymysql.connect(host“xxx”, user“root”, password“xxx”, db“userprofiles”, charset“utf8”,autocommitTrue) 原因 autocommit的参数必须是True或者False True:在execute时就会立即向数据库发出操作请求…...