八种单例模式
文章目录
- 1.单例模式基本介绍
- 1.介绍
- 2.单例模式八种方式
- 2.饿汉式(静态常量,推荐)
- 1.基本步骤
- 1.构造器私有化(防止new)
- 2.类的内部创建对象
- 3.向外暴露一个静态的公共方法
- 2.代码实现
- 3.优缺点分析
- 3.饿汉式(静态代码块,推荐)
- 1.代码实现
- 2.优缺点分析
- 4.懒汉式(线程不安全,实际开发不要使用)
- 1.代码实现
- 2.优缺点分析
- 5.懒汉式(线程安全,同步方法,实际开发不推荐使用)
- 1.代码实现
- 2.优缺点分析
- 6.懒汉式(线程安全,同步代码块,解决不了同步问题)
- 1.介绍
- 2.优缺点分析
- 7.双重检查(推荐使用)
- 1.代码实现
- 2.关于volatile关键字
- 使用 `volatile` 的常见场景
- 复合操作的限制
- 总结
- 3.优点分析
- 8.静态内部类实现(推荐使用)
- 1.前置知识
- 1.外部类被装载,静态内部类不会被装载
- 2.当调用静态内部类的属性时,静态内部类会被装载且只会被装载一次
- 3.在类装载的时候是线程安全的
- 2.代码实现
- 3.优点分析
- 9.枚举实现(推荐使用)
- 1.代码实现
- 2.优缺点分析
- 10.单例模式总结
- 1.Runtime就使用了饿汉式的单例模式
- 2.注意事项和细节
1.单例模式基本介绍
1.介绍
2.单例模式八种方式
2.饿汉式(静态常量,推荐)
1.基本步骤
1.构造器私有化(防止new)
2.类的内部创建对象
3.向外暴露一个静态的公共方法
2.代码实现
package com.sun.type1;/*** Description: 单例模式饿汉式(静态变量)* @Author sun* @Create 2024/5/26 19:28* @Version 1.0*/
public class Singleton01 {public static void main(String[] args) {// 通过公有的静态方法,获取实例Singleton instance = Singleton.getInstance();Singleton instance1 = Singleton.getInstance();System.out.println(instance1 == instance); // 返回的是true}
}class Singleton {// 1.构造器私有化private Singleton() {}// 2.本类的内部创建对象实例private final static Singleton instance = new Singleton();// 3.暴露一个公有的静态方法,返回实例对象public static Singleton getInstance() {return instance;}
}
3.优缺点分析
3.饿汉式(静态代码块,推荐)
1.代码实现
package com.sun.type1;/*** Description: 单例模式饿汉式(静态代码块)* @Author sun* @Create 2024/5/26 19:49* @Version 1.0*/
public class Singleton02Test {public static void main(String[] args) {// 通过公有的静态方法,获取实例Singleton02 instance = Singleton02.getInstance();Singleton02 instance1 = Singleton02.getInstance();System.out.println(instance1 == instance); // 返回的是true}
}class Singleton02 {// 1.构造器私有化private Singleton02() {}// 2.本类的内部有一个静态属性private static Singleton02 instance;// 3.使用静态代码块为静态属性初始化static {instance = new Singleton02();}// 4.暴露一个公有的静态方法,返回实例对象public static Singleton02 getInstance() {return instance;}
}
2.优缺点分析
4.懒汉式(线程不安全,实际开发不要使用)
1.代码实现
package com.sun.type3;/*** Description: 单例模式懒汉式(线程不安全)* @Author sun* @Create 2024/5/26 20:02* @Version 1.0*/
public class Singleton03Test {public static void main(String[] args) {Singleton instance = Singleton.getInstance();Singleton instance1 = Singleton.getInstance();System.out.println(instance1 == instance);}
}class Singleton {// 1.构造器私有化private Singleton() {}// 2.静态属性,存放本类对象private static Singleton instance;// 3.静态的公有方法,当使用到该方法时才会去创建instancepublic static Singleton getInstance() {// 当静态属性没有被赋值的时候再去创建if (instance == null) {instance = new Singleton();}// 如果这个静态属性被初始化过了,就直接返回,保证是单例的return instance;}
}
2.优缺点分析
5.懒汉式(线程安全,同步方法,实际开发不推荐使用)
1.代码实现
package com.sun.type4;/*** Description: 单例模式懒汉式(线程安全,同步方法)* @Author sun* @Create 2024/5/26 20:15* @Version 1.0*/
public class Singleton04Test {public static void main(String[] args) {Singleton instance = Singleton.getInstance();Singleton instance1 = Singleton.getInstance();System.out.println(instance1 == instance);}
}class Singleton {// 1.构造器私有化private Singleton() {}// 2.静态属性,存放本类对象private static Singleton instance;// 3.静态的公有方法,当使用到该方法时才会去创建instance,使用synchronized实现线程安全public static synchronized Singleton getInstance() {// 当静态属性没有被赋值的时候再去创建if (instance == null) {instance = new Singleton();}// 如果这个静态属性被初始化过了,就直接返回,保证是单例的return instance;}
}
2.优缺点分析
6.懒汉式(线程安全,同步代码块,解决不了同步问题)
1.介绍
2.优缺点分析
7.双重检查(推荐使用)
1.代码实现
package com.sun.type6;/*** Description: 双重检查* @Author sun* @Create 2024/5/26 20:15* @Version 1.0*/
public class Singleton06Test {public static void main(String[] args) {Singleton instance = Singleton.getInstance();Singleton instance1 = Singleton.getInstance();System.out.println(instance1 == instance);}
}class Singleton {// 1.构造器私有化private Singleton() {}// 2.静态属性,存放本类对象,使用volatile防止指令重排序private static volatile Singleton instance;// 3.静态的公有方法,当使用到该方法时才会去创建instancepublic static Singleton getInstance() {// 先检查一次静态属性是否为空,这样可以过滤掉一部分if (instance == null) {// 如果为空,则进入同步代码块创建对象,由于还是会有多个线程进来,所以在内部需要二次检查synchronized (Singleton.class) {// 在此完成双重检查if (instance == null) {instance = new Singleton();}}}// 如果这个静态属性被初始化过了,就直接返回,保证是单例的return instance;}
}
2.关于volatile关键字
使用 volatile
的常见场景
-
直接赋值:
- 设置标志位,如控制线程的开始或停止。
- 单个配置值的更新,这个值被多个线程读取。
例如,一个线程控制开关:
public class TaskRunner implements Runnable {private volatile boolean stop = false;public void run() {while (!stop) {// 执行任务}}public void stop() {stop = true;} }
-
单一读取操作:
- 在这种情况下,
volatile
保证了每次读取操作都从主内存中获取最新值,而不是从线程的本地缓存。
- 在这种情况下,
复合操作的限制
如果操作涉及到对变量的读取、修改和写回(如 a++
),则 volatile
不能保证操作的原子性。这类操作需要使用 synchronized
或 java.util.concurrent.atomic
包中的原子类。例如,对一个计数器进行增加操作:
public class Counter {private volatile int count = 0; // 这是错误的做法,对于 count++ 操作public void increment() {count++; // 这不是线程安全的}
}
在上面的代码中,count++
操作实际上是三个步骤:读取 count
的当前值,增加 1,然后写回新值。这三个步骤不是原子操作,因此即使 count
被声明为 volatile
,在多线程环境中也可能导致不正确的结果。
总结
总之,当你的需求仅限于确保多线程之间对单个变量直接赋值操作的可见性和有序性时,使用 volatile
是合适的。然而,对于需要多个步骤或基于当前值的修改的操作,你需要使用更强的同步机制。
3.优点分析
8.静态内部类实现(推荐使用)
1.前置知识
1.外部类被装载,静态内部类不会被装载
2.当调用静态内部类的属性时,静态内部类会被装载且只会被装载一次
3.在类装载的时候是线程安全的
2.代码实现
package com.sun.type7;/*** Description: 单例模式(静态内部类实现)* @Author sun* @Create 2024/5/26 20:51* @Version 1.0*/
public class Singleton07Test {public static void main(String[] args) {Singleton instance = Singleton.getInstance();Singleton instance1 = Singleton.getInstance();System.out.println(instance1 == instance);}
}class Singleton {// 1.构造器私有化private Singleton() {}// 2.一个静态内部类,该类有一个静态属性,存放外部类的对象private static class SingletonInstance {public static final Singleton INSTANCE = new Singleton();}// 3.静态的公有方法,当要使用时调用内部类的静态属性,此时静态内部类会被装载,且只会被装载一次public static Singleton getInstance() {return SingletonInstance.INSTANCE;}
}
3.优点分析
9.枚举实现(推荐使用)
1.代码实现
package com.sun.type8;/*** Description: 单例模式(静态内部类实现)* @Author sun* @Create 2024/5/26 20:51* @Version 1.0*/
public class Singleton08Test {public static void main(String[] args) {Singleton instance = Singleton.INSTANCE;Singleton instance2 = Singleton.INSTANCE;System.out.println(instance2 == instance);}
}enum Singleton {// 这个就相当于调用无参构造创建了这个类的一个对象,可以实现单例模式INSTANCE;
}
2.优缺点分析
10.单例模式总结
1.Runtime就使用了饿汉式的单例模式
2.注意事项和细节
相关文章:

八种单例模式
文章目录 1.单例模式基本介绍1.介绍2.单例模式八种方式 2.饿汉式(静态常量,推荐)1.基本步骤1.构造器私有化(防止new)2.类的内部创建对象3.向外暴露一个静态的公共方法 2.代码实现3.优缺点分析 3.饿汉式(静态…...

禅道密码正确但是登录异常处理
禅道密码正确,但是登录提示密码错误的异常处理 排查内容 # 1、服务器异常,存储空间、数据库异常 # 2、服务异常,文件丢失等异常问题定位 # 1、df -h 排查服务器存储空间 # 2、根据my.php排查数据库连接是否正常 # 3、修改my.pho,debugtrue…...

Go微服务: Nacos的搭建和基础API的使用
Nacos 概述 文档:https://nacos.io/docs/latest/what-is-nacos/搭建:https://nacos.io/docs/latest/quickstart/quick-start-docker/有很多种搭建方式,我们这里使用 docker 来搭建 Nacos 的搭建 这里,我们选择单机模式…...
基于Hadoop的城市公共交通大数据时空分析
基于Hadoop的城市公共交通大数据时空分析 “Spatio-temporal Analysis of Urban Public Transportation Big Data based on Hadoop” 完整下载链接:基于Hadoop的城市公共交通大数据时空分析 文章目录 基于Hadoop的城市公共交通大数据时空分析摘要第一章 引言1.1 研究背景1.2 …...

DNS服务的部署与配置(2)
1、dns的安装及开启 dnf install bind.x86_64 -y #安装 #Berkeley Internet Name Domain (BIND) systemctl enable --now named #启用dns服务,服务名称叫named firewall-cmd --permanent --add-servicedns #火墙设置 firewall-cmd --reload …...

MySql--SQL语言
目录 SQl---DDL 结构定义 创建、删除 数据库 代码 运行 设计表 数据类型 整数 浮点数 主键 约束 主键自增长 默认值 字段注释 创建、删除 表 代码 运行 代码 代码 运行 SQL---DML 数据操纵 插入数据 代码 运行 代码 运行 代码 运行 代码 …...

【网络安全】2030年十大新兴网络安全威胁
欧盟网络安全局(ENISA)已发布了一份全面的清单,列出了预计到2030年将影响数字领域的十大新兴网络安全威胁。 该预测是为期八个月的广泛研究的成果,融合了ENISA前瞻专家小组、CSIRTs网络以及欧盟CyCLONe专家的见解。 这项研究突显…...

python数据分析-CO2排放分析
导入所需要的package import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import datetime %matplotlib inline plt.rcParams[font.sans-serif] [KaiTi] #中文 plt.rcParams[axes.unicode_minus] False #负号 数据清洗…...

2024宝藏工具EasyRecovery数据恢复软件免费版本下载
在这个数字化的时代,数据已经成为我们生活中的重中之重。无论是工作中的重要文件,还是手机中珍贵的照片,我们都依赖着这些数据。然而,数据丢失的情况时有发生,可能是误删,可能是设备故障,更可能…...
【EventSource错误解决方案】设置Proxy后SSE发送的数据只在最后接收到一次,并且数据被合并
【EventSource错误解决方案】设置Proxy后SSE发送的数据只在最后接收到一次,并且数据被合并 出错描述 出错原因与解决方案 出错描述 SSE前后端一切正常,但是fetchEventSource 的onmessage回调函数只在所有流都发送完毕后,才会执行一次。 前…...
如何在linux命令行(终端)执行ipynb 文件。可以不依赖jupyter
1.安装 runipy pip install runipy 2.终端运行 runipy <YourNotebookName>.ipynb 在终端命令行执行shell脚本,(也可以在crontab 中执行): (base) [recommendapp-0-5-B-006 script]$ cat run1.sh #!/bin/bashcd /home/recom…...

基于YOLOv8的车牌检测与识别(CCPD2020数据集)
前言 本篇博客主要记录在autodl服务器中基于yolov8实现车牌检测与识别,以下记录实现全过程~ yolov8源码:GitHub - ultralytics/ultralytics: NEW - YOLOv8 🚀 in PyTorch > ONNX > OpenVINO > CoreML > TFLite 一、环境配置 …...

驱动开发之新字符设备驱动开发
1.前言 register_chrdev 和 unregister_chrdev 这两个函数是老版本驱动使用的函数,现在新的 字符设备驱动已经不再使用这两个函数,而是使用 Linux 内核推荐的新字符设备驱动 API 函数。 旧版本的接口使用,感兴趣可以看下面这个博客&#…...
【JMU】21编译原理期末笔记
本拖延症晚期患者不知不觉已经有半年没写博客了,天天不知道在忙什么。 乘着期末周前赶紧先把编译原理上传了,我记得我这科是86分,有点小遗憾没上90,但是总体不错。 链接:https://pan.baidu.com/s/1gO8pT7paHv1lkM_ZpkI…...

就业信息|基于SprinBoot+vue的就业信息管理系统(源码+数据库+文档)
就业信息管理系统 目录 基于SprinBootvue的就业信息管理系统 一、前言 二、系统设计 三、系统功能设计 1前台功能模块 2后台功能模块 4.2.1管理员功能 4.2.2学生功能 4.2.3企业功能 4.2.4导师功能 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设…...

一.架构设计
架构采用 ddd 架构,不同于传统简单的三层的架构,其分层的思想对于大家日后都是很有好处的,会给大家的思想层级,提高很多。 传统的项目 现有的架构 采取ddd架构,给大家在复杂基础上简化保留精髓,一步步进行…...

<学习笔记>从零开始自学Python-之-实用库篇(一)-pyscript
由Anaconda创建的PyScript是一项实验性的但很有前途的新技术,它使python运转时在支撑WebAssembly的浏览器中作为一种脚本言语运用。 每个现代常用的浏览器现在都支撑WebAssembly,这是许多言语(如C、C和Rust)能够编译的高速运转时…...
Vue项目中npm run build 卡住不执行的几种情况(实战版)
方法一 一:比较常见是镜像导致的原因 我们可以找到build/check-versions文件 将这段代码注释,重新运行就可以解决这个问题 if (shell.which(npm)) {versionRequirements.push({name: npm,currentVersion: exec(npm --version),versionRequirement: packageConfig.en…...

《Python源码剖析》之pyc文件
前言 前面我们主要围绕pyObject和pyTypeObject聊完了python的内建对象部分,现在我们将开启新的篇章—python虚拟机,将聚焦在python的执行部分,搞懂从“代码”到“执行”的过程。开启新的篇章之前,你也许会有一个疑惑:我…...

Python零基础-中【详细】
接上篇继续: Python零基础-上【详细】-CSDN博客 目录 十、函数式编程 1、匿名函数lambda表达式 (1)匿名函数理解 (2)lambda表达式的基本格式 (3)lambda表达式的使用场景 (4&…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...

mac:大模型系列测试
0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...

JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
验证redis数据结构
一、功能验证 1.验证redis的数据结构(如字符串、列表、哈希、集合、有序集合等)是否按照预期工作。 2、常见的数据结构验证方法: ①字符串(string) 测试基本操作 set、get、incr、decr 验证字符串的长度和内容是否正…...