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

07 创建型模式-单例模式

1.单例模式介绍

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,此模式保证
某个类在运行期间,只有一个实例对外提供服务,而这个类被称为单例类。

2.使用单例模式要做的两件事
  1. 保证一个类只有一个实例
  2. 为该实例提供一个全局访问节点
3. 单例模式结构

在这里插入图片描述

4.1 单例模式之饿汉式:

在类加载期间初始化静态实例,保证 instance 实例的创建是线程安全的 ( 实例在
类加载时实例化,有JVM保证线程安全).
特点: 不支持延迟加载实例(懒加载) , 此中方式类加载比较慢,但是获取实例对象
比较快。

问题: 该对象足够大的话,而一直没有使用就会造成内存的浪费。

public class Singleton_01 {//1. 私有构造方法private Singleton_01(){}//2. 在本类中创建私有静态的全局对象private static Singleton_01 instance = new Singleton_01();//3. 提供一个全局访问点,供外部获取单例对象public static Singleton_01 getInstance(){return instance;}}
4.2懒汉式(线程不安全)

此种方式的单例实现了懒加载,只有调用getInstance方法时 才创建对象.但是如
果是多线程情况,会出现线程安全问题.

public class Singleton_02 {//1. 私有构造方法private Singleton_02(){}//2. 在本类中创建私有静态的全局对象private static Singleton_02 instance;//3. 通过判断对象是否被初始化,来选择是否创建对象public static Singleton_02 getInstance(){if(instance == null){instance = new Singleton_02();}return instance;}}

注意:
假设在单例类被实例化之前,有两个线程同时在获取单例对象,线程A在执
行完if (instance == null) 后,线程调度机制将 CPU 资源分配给线程B,此
时线程B在执行 if (instance == null)时也发现单例类还没有被实例化,这样
就会导致单例类被实例化两次。为了防止这种情况发生,需要对
getInstance() 方法同步处理。改进后的懒汉模式.

懒汉式(线程安全)

原理: 使用同步锁 synchronized 锁住 创建单例的方法 ,防止多个线程同时调
用,从而避免造成单例被多次创建。

public class Singleton_03 {//1. 私有构造方法private Singleton_03(){}//2. 在本类中创建私有静态的全局对象private static Singleton_03 instance;//3. 通过添加synchronize,保证多线程模式下的单例对象的唯一性public static synchronized Singleton_03 getInstance(){if(instance == null){instance = new Singleton_03();}return instance;}}

缺点
懒汉式的缺点也很明显,我们给 getInstance() 这个方法加了一把大锁
(synchronzed),导致这个函数的并发度很低。量化一下的话,并发度
是 1,也就相当于串行操作了。而这个函数是在单例使用期间,一直会被调
用。如果这个单例类偶尔会被用到,那这种实现方式还可以接受。但是,
如果频繁地用到,那频繁加锁、释放锁及并发度低等问题,会导致性能瓶
颈,这种实现方式就不可取了。

双重校验

饿汉式不支持延迟加载,懒汉式有性能问题,不支持高并发。那我们再来看一
种既支持延迟加载、又支持高并发的单例实现方式,也就是双重检测实现方
式。

实现步骤:

  1. 在声明变量时使用了 volatile 关键字,其作用有两个:
    保证变量的可见性:当一个被volatile关键字修饰的变量被一个线程修改的时
    候,其他线程可以立刻得到修改之后的结果。
    屏蔽指令重排序:指令重排序是编译器和处理器为了高效对程序进行优化的手
    段,它只能保证程序执行的结果时正确的,但 是无法保证程序的操作顺序与代
    码顺序一致。这在单线程中不会构成问题,但是在多线程中就会出现问题。
  2. 将同步方法改为同步代码块. 在同步代码块中使用二次检查,以保证其不被
    重复实例化 同时在调用getInstance()方法时不进行同步锁,效率高。
public class Singleton_04 {//1. 私有构造方法private Singleton_04(){}//2. 使用 volatile保证变量的可见性private volatile static Singleton_04 instance = null;//3. 对外提供静态方法获取对象public static Singleton_04 getInstance(){//第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实例if(instance == null){synchronized (Singleton_04.class){//抢到锁之后再次进行判断是否为nullif(instance == null){instance = new Singleton_04();}}}return instance;}}
静态内部类

原理 根据静态内部类 的特性(外部类的加载不影响内部类),同时解决了按
需加载、线程安全的问题,同时实现简洁。

  1. 在静态内部类里创建单例,在装载该内部类时才会去创建单例
  2. 线程安全:类是由 JVM 加载,而 JVM 只会加载1遍,保证只有1个单例
public class Singleton_05 {private static class SingletonHandler{private static Singleton_05 instance = new Singleton_05();}private Singleton_05(){}public static Singleton_05 getInstance(){return SingletonHandler.instance;}}
反射对于单例的破坏

反射技术过于强大,它可以通过 setAccessible() 来修改构造器,字段,方法
的可见性。单例模式的构造方法是私有的,如果将其可见性设为 public ,那么
将无法控制对象的创建。

public class Test_Reflect {public static void main(String[] args) {try {//反射中,欲获取一个类或者调用某个类的方法,首先要获取到该类的Class 对象。Class<Singleton_05> clazz = Singleton_05.class;//getDeclaredXxx: 不受权限控制的获取类的成员.Constructor c = clazz.getDeclaredConstructor(null);//设置为true,就可以对类中的私有成员进行操作了c.setAccessible(true);Object instance1 = c.newInstance();Object instance2 = c.newInstance();System.out.println(instance1 == instance2);} catch (Exception e) {e.printStackTrace();}}}

解决方法之一: 在单例类的构造方法中 添加判断 instance != null 时,直接抛
出异常

public class Singleton_05 {private static class SingletonHandler{private static Singleton_05 instance = new Singleton_05();}private Singleton_05(){if(SingletonHandler.instance != null){throw new RuntimeException("不允许非法访问!");}}public static Singleton_05 getInstance(){return SingletonHandler.instance;}
}

上面的这种方式使代码简洁性遭到破坏,设计不够优雅.

序列化对于单例的破坏
public class Test_Serializable {@Testpublic void test() throws Exception{//序列化对象输出流ObjectOutputStream oos = new ObjectOutputStream(newFileOutputStream("tempFile.obj"));oos.writeObject(Singleton.getInstance());//序列化对象输入流File file = new File("tempFile.obj");ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));Singleton Singleton = (Singleton) ois.readObject();System.out.println(Singleton);System.out.println(Singleton.getInstance());//判断是否是同一个对象System.out.println(Singleton.getInstance() == Singleton);//false}
}class Singleton implements Serializable{private volatile static Singleton singleton;private Singleton() {}public static Singleton getInstance() {if (singleton == null) {synchronized (Singleton.class) {if (singleton == null) {singleton = new Singleton();}}}return singleton;}
}

输出结构为false,说明:
通过对Singleton的序列化与反序列化得到的对象是一个新的对象,这就 破坏了
Singleton的单例性 。

解决方案:

/**
* 解决方案:只要在Singleton类中定义readResolve就可以解决该问题
* 程序会判断是否有readResolve方法,如果存在就在执行该方法,如果不存在-
-就创建一个对象
*/
private Object readResolve() {return singleton;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
readOrdinaryObject方法的代码片段

private Object readOrdinaryObject(boolean unshared)
throws IOException
{
//此处省略部分代码
Object obj;
try {
//通过反射创建的这个obj对象,就是本方法要返回的对象,也
可以暂时理解为是ObjectInputStream的readObject返回的对象。
//isInstantiable:如果一个serializable的类可以在运行
时被实例化,那么该方法就返回true
//desc.newInstance:该方法通过反射的方式调用无参构造方
法新建一个对象。
obj = desc.isInstantiable() ? desc.newInstance()
: null;
} catch (Exception ex) {
throw (IOException) new InvalidClassException(
desc.forClass().getName(),
"unable to create instance").initCause(ex);
}
return obj;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5 枚举(推荐方式)

在这里插入图片描述

public enum Singleton_06{INSTANCE;private Object data;public Object getData() {return data;}public void setData(Object data) {this.data = data;}public static Singleton_06 getInstance(){return INSTANCE;}
}

在这里插入图片描述
在这里插入图片描述

相关文章:

07 创建型模式-单例模式

1.单例模式介绍 单例模式&#xff08;Singleton Pattern&#xff09;是 Java 中最简单的设计模式之一&#xff0c;此模式保证 某个类在运行期间&#xff0c;只有一个实例对外提供服务&#xff0c;而这个类被称为单例类。 2.使用单例模式要做的两件事 保证一个类只有一个实例…...

RunnerGo 支持UI自动化的测试平台

RunnerGo提供从API管理到API性能再到可视化的API自动化、UI自动化测试功能模块&#xff0c;覆盖了整个产品测试周期。 RunnerGo UI自动化基于Selenium浏览器自动化方案构建&#xff0c;内嵌高度可复用的测试脚本&#xff0c;测试团队无需复杂的代码编写即可开展低代码的自动化…...

LLM ReAct: 将推理和行为相结合的通用范式 学习记录

LLM ReAct 什么是ReAct? LLM ReAct 是一种将推理和行为相结合的通用范式,可以让大型语言模型(LLM)根据逻辑推理(Reason),构建完整系列行动(Act),从而达成期望目标。LLM ReAct 可以应用于多种语言和决策任务,例如问答、事实验证、交互式决策等,提高了 LLM 的效率、…...

聊聊分布式架构08——SpringBoot开启微服务时代

目录 微服务架构时代 快速入门 入门详解 SpringBoot的自动配置 石器时代&#xff1a;XML配置bean 青铜时代&#xff1a;SpringConfig 铁器时代&#xff1a;AutoConfigurationImportSelector 手写简单Starter SpringApplication启动原理 微服务架构时代 Spring Boot的…...

Vue项目中集成TinyMCE富文本编辑器(图片批量上传等)

TinyMCE富文本在Vue中的使用 关于TinyMCE 实现效果 安装使用TinyMCE 第一步 第二步 1.官网申请Your Tiny API Key&#xff0c;并且配置访问域名&#xff1a; 2.使用css隐藏(这个就不讲了&#xff0c;不推荐使用) 3.全部由本地加载(推荐) 第三步(汉化包) 第四步(封装组…...

前端数据可视化之【title、legend、tooltip、toolbox 】配置项

目录 &#x1f31f;Echarts配置项&#x1f31f;Echarts配置项之 title组件&#x1f31f;Echarts配置项之 legend组件&#x1f31f;Echarts配置项之 tooltip组件&#x1f31f;Echarts配置项之 toolbox组件&#x1f31f;写在最后 &#x1f31f;Echarts配置项 ECharts开源来自百度…...

microcom串口调试工具使用

microcom串口助手使用介绍 microcom是一个在终端中使用的串口助手&#xff0c;类似平常使用SSCOM一样的东西&#xff0c;不过是在终端中使用而已。 使用的是busybox构建的文件系统 microcom源码路径&#xff1a;busybox/miscutils/microcom.c microcom 参数&#xff1a; [r…...

深入了解Golang:基本语法与核心特性解析

1. 引言 Golang&#xff08;Go&#xff09;是谷歌开发的一门开源编程语言&#xff0c;于2007年首次公开亮相&#xff0c;随后在2012年正式发布。Golang以其简洁、高效和可靠的设计而备受开发者青睐。作为一门编译型语言&#xff0c;Golang具有静态类型和垃圾回收功能&#xff…...

短视频矩阵系统源码---php搭建

一、智能剪辑、矩阵分发、无人直播、爆款文案于一体独立应用开发 抖去推----主要针对本地生活的----移动端(小程序软件系统&#xff0c;目前是全国源头独立开发)&#xff0c;开发功能大拆解分享&#xff0c;功能大拆解&#xff1a; &#xff08;1&#xff09;数据概览&#x…...

mysql 查询表字段名,注释 , 以及sql拼接查询出的内容

#sql查询字段名&#xff0c;注释操作拼接 #查询字段名和注释 select COLUMN_NAME,COLUMN_COMMENT from information_schema.COLUMNS where table_name 表名 and table_schema 库名 order by ordinal_position #查询整个内容 select * from information_schema.COLUMNS wh…...

【JavaEE】_Servlet API

目录 1. HttpServlet 1.1 init方法 1.2 destroy方法 1.3 service方法 1.4 Servlet的生命周期 1.5 代码示例 1.5.1 使用postman构造请求 1.5.2 使用ajax构造请求 2. HttpServletRequest 2.1 核心方法 2.2 代码示例1&#xff1a;打印请求信息 3. 前端给后端传参 3.1…...

macOS下matplotlib如何显示中文字体?

一般要显示中文会使用&#xff1a; plt.rcParams[font.sans-serif][SimHei] #用来正常显示中文标签 plt.rcParams[axes.unicode_minus]False #用来正常显示负号不过在macOS下通常会显示方块字&#xff1a; 解决方案&#xff1a; 把上面两句注释掉&#xff0c;更换为&#xf…...

7-Zip怎么设置字典大小 单词大小 固实数据大小,把大文件9.35G压缩成小1.56G

环境: Win10 专业版 7-Zip v23.01 问题描述: 7-Zip怎么设置字典大小 单词大小 固实数据大小,把大文件9.28G压缩成小1.56G 解决方案: 要在7-Zip中设置字典大小、单词大小和固实数据大小,可以按照以下步骤进行操作: 打开7-Zip文件管理器,并导航到你要压缩的文件所在的…...

使用CPR库和Python编写程序

以下是一个使用CPR库和Python编写的爬虫程序&#xff0c;用于爬取。此程序使用了proxy的代码。 import requests from cpr import CPR ​ def get_proxy():url "https://www.duoip.cn/get_proxy"headers {"User-Agent": "Mozilla/5.0 (Windows NT …...

axios 请求的缓存封装

前言 咱们的网站或者程序&#xff0c;每一个页面和操作都需要请求后端接口来获取响应和渲染页面&#xff0c;抛开post请求方式的接口不说&#xff0c;部分get请求得到的数据&#xff0c;短时间内不会更新&#xff0c;或者短时间得到的响应数据不会变化&#xff0c;这个时候就可…...

Oracle性能调优实践中的几点心得

很多的时侯&#xff0c;做OracleDBA的我们&#xff0c;当应用管理员向我们通告现在应用很慢、数据库很慢的时侯&#xff0c;我们到数据库时做几个示例的Select也发现同样的问题时&#xff0c;有些时侯我们会无从下手&#xff0c;因为我们认为数据库的各种命种率都是满足Oracle文…...

勒索病毒最新变种.halo勒索病毒来袭,如何恢复受感染的数据?

引言&#xff1a; 在当今数字化时代&#xff0c;勒索病毒的威胁不断升级&#xff0c;其中.halo勒索病毒引起了广泛关注。本文91数据恢复将深入研究.halo勒索病毒的特点&#xff0c;探讨如何有效地恢复被其加密的数据文件&#xff0c;并分享预防这一威胁的关键措施。 .halo勒索…...

大厂秋招真题【前缀和】美团20230826秋招T5-平均数为k的最长连续子数组

文章目录 【前缀和】美团20230826秋招T5-平均数为k的最长连续子数组题目描述与示例题目描述输入描述输出描述示例输入输出说明 解题思路代码PythonJavaC时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 【前缀和】美团20230826秋招T5-平均数为k的最长连续子数组 题目描…...

bazel远程构建(Remote Execution) --- linux安装Redis

采用源码安装方式 下载地址&#xff1a;Download | Redis&#xff0c;下载最新稳定版本。 step1: 下载最新稳定版本 wget https://download.redis.io/redis-stable.tar.gz step2: 解压安装 tar -xzvf redis-stable.tar.gz cd redis-stable make 执行完 make 命令后&#…...

Maven在开发中的使用及理解

在JAVA项目中&#xff0c;我们通常需要对项目的构建和依赖进行管理&#xff0c;这个时候我们就需要MAVEN来对项目进行支持。 一.MAVEN构建 在整个MAVEN构建的过程中包含以下环节&#xff0c;也对应IDEA中MAVEN的对应功能。 清理Maven Clean 清理&#xff0c;则代表删除上一…...

终极微信自动化指南:如何用wxauto轻松管理你的微信消息

终极微信自动化指南&#xff1a;如何用wxauto轻松管理你的微信消息 【免费下载链接】wxauto Windows版本微信客户端&#xff08;非网页版&#xff09;自动化&#xff0c;可实现简单的发送、接收微信消息&#xff0c;简单微信机器人 项目地址: https://gitcode.com/gh_mirrors…...

从静态到动态:用sd-webui-animatediff解锁AI视频创作的魔法配方 [特殊字符]

从静态到动态&#xff1a;用sd-webui-animatediff解锁AI视频创作的魔法配方 &#x1f3ac; 【免费下载链接】sd-webui-animatediff AnimateDiff for AUTOMATIC1111 Stable Diffusion WebUI 项目地址: https://gitcode.com/gh_mirrors/sd/sd-webui-animatediff 想象一下&…...

Mac M1芯片上,用Conda和pip搞定PyTorch GPU加速的保姆级避坑指南

Mac M1芯片上&#xff0c;用Conda和pip搞定PyTorch GPU加速的保姆级避坑指南 当苹果推出搭载M1芯片的Mac设备时&#xff0c;整个开发者社区都为它的性能潜力感到兴奋。然而&#xff0c;对于深度学习开发者来说&#xff0c;最初的日子并不轻松——许多工具链尚未适配ARM架构。如…...

OpenAI发布GPT-5.5,数学与编程能力大幅跃升

OpenAI近日正式推出新一代大语言模型GPT-5.5&#xff0c;该模型在数学解题与代码编写方面相较前代产品有显著提升。GPT-5.5的发布时间恰好在竞争对手Anthropic推出其最新大语言模型一周之后。OpenAI为用户提供两种版本选择&#xff1a;标准版以及功能更强、定价更高的GPT-5.5 P…...

Windows Shell扩展技术解析:HashCheck如何实现文件完整性验证

Windows Shell扩展技术解析&#xff1a;HashCheck如何实现文件完整性验证 【免费下载链接】HashCheck HashCheck Shell Extension for Windows with added SHA2, SHA3, and multithreading; originally from code.kliu.org 项目地址: https://gitcode.com/gh_mirrors/ha/Hash…...

如何快速掌握音频频谱分析:Spek声学工具终极指南

如何快速掌握音频频谱分析&#xff1a;Spek声学工具终极指南 【免费下载链接】spek Acoustic spectrum analyser 项目地址: https://gitcode.com/gh_mirrors/sp/spek 你是否曾经好奇音乐中的高低频分布&#xff1f;或者想检查录音中的噪声问题&#xff1f;Spek就是你的答…...

数据分析学习01(黑马)-Linux基础

一.操作系统概述 计算机分类 计算机一般分为个人计算机&#xff08;笔记、台式机&#xff09;与 企业级服务器&#xff08;1U、2U、机柜、塔式、刀片&#xff09;两种形式。 计算机组成 标题 计算机资源分为2 部分&#xff1a;硬件资源、软件资源 硬件资源&#xff1a;所谓的硬…...

从阿里云到内网:一套Chrony配置搞定混合云环境的时间同步难题

混合云环境下基于Chrony的分层时间同步架构设计与实践 在数字化转型浪潮中&#xff0c;企业IT基础设施往往呈现混合云架构——既有公有云资源&#xff0c;又保留私有数据中心&#xff0c;同时存在严格隔离的开发测试环境。这种架构下&#xff0c;时间同步这一看似基础却至关重要…...

2026 SMT贴片线数字孪生开发平台选型

SMT贴片线数字孪生平台选型需聚焦“高精度、高节拍、高复杂度”特性。专项能力一&#xff1a;微米级精度的“贴装过程仿真”高精度模型导入&#xff1a;能直接导入贴片机头部组件的精密CAD模型&#xff08;SolidWorks、CATIA&#xff09;&#xff0c;保持装配约束。关节运动与I…...

从JDK动态代理到CGLIB:Spring事务@EnableTransactionManagement中proxyTargetClass参数的真实影响

从JDK动态代理到CGLIB&#xff1a;Spring事务EnableTransactionManagement中proxyTargetClass参数的真实影响 在Spring框架的事务管理机制中&#xff0c;EnableTransactionManagement注解的proxyTargetClass参数往往被开发者简单理解为"是否强制使用CGLIB代理"的开关…...