设计模式之单例模式(通俗易懂--代码辅助理解【Java版】)

news/2024/9/18 7:04:02/ 标签: java, 单例模式

文章目录

  • 设计模式概述
  • 1、单例模式概述
  • 2、懒汉式:
  • 3、饿汉式
  • 4、懒汉式:解决反射、序列化反序列化问题
  • 5、懒汉式DCL(推荐)
  • 6、应用场景
  • 7、单例线程池实现
  • 8、总结

设计模式概述

创建型模式:工厂方法、抽象方法、建造者、原型、单例。
结构型模式有:适配器、桥接、组合、装饰器、外观、享元、代理。
行为型模式有:责任链、命令、解释器、迭代器、中介、备忘录、观察者、状态、策略、模板方法、访问者。
常用设计模式:
单例模式、工厂模式、代理模式、策略模式&模板模式、门面模式、责任链模式、装饰器模式、组合模式、builder模式。

1、单例模式概述

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。
注意:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例

2、懒汉式:

java">/*** 单例设计模式:确保一个类只有一个对象实例,并提供一个全局访问点* 懒汉式:* 是否 Lazy 初始化:是* 是否多线程安全:否*/
public class Signleton {private static Signleton signleton;private Signleton(){}//可以通过synchronized关键字保证线程安全public static Signleton getSignleton(){if(signleton == null){signleton = new Signleton();}return signleton;}
}

3、饿汉式

java">/*** 单例设计模式:确保一个类只有一个对象实例,并提供一个全局访问点* 饿汉式:* 是否 Lazy 初始化:否* 是否多线程安全:是*/
class Signleton1{private static Signleton1 signleton1 = new Signleton1();private Signleton1(){}public static Signleton1 getSignleton1(){return signleton1;}
}

4、懒汉式:解决反射、序列化反序列化问题

java">/*** 单例设计模式:确保一个类只有一个对象实例,并提供一个全局访问点* 懒汉式:* 是否 Lazy 初始化:是* 是否多线程安全:否*/
public class Signleton implements Serializable {private static final long serialVersionUID = 1L;private static Signleton signleton;private Signleton() {// 防止反射if (signleton != null) {throw new RuntimeException();}}// 可以通过synchronized关键字保证线程安全public static Signleton getSignleton() {if (signleton == null) {signleton = new Signleton();}return signleton;}/*序列化:当一个对象被序列化时,Java 将该对象的状态写入一个字节流。反序列化:当字节流被反序列化时,Java 将创建一个新的对象实例,并将字节流中的数据填充到这个新实例中。readResolve 方法:在对象被反序列化之后,Java 会调用这个方法。如果该方法存在,返回的对象将代替默认反序列化过程中创建的新对象。*/private Object readResolve() {return signleton;}}/*** 反射测试*/@Testpublic void test(){//获取单例Signleton signleton = Signleton.getSignleton();Signleton signleton1 = Signleton.getSignleton();System.out.println(signleton.hashCode());System.out.println(signleton1.hashCode());//通过反射破坏单例try {Class<?> aClass = Class.forName("design.patterns.Signleton");Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();declaredConstructor.setAccessible(true);Signleton signleton2 = (Signleton) declaredConstructor.newInstance();System.out.println(signleton2.hashCode());} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException |InvocationTargetException e) {e.printStackTrace();}}/*** 序列化测试*/@Testpublic void test1(){//获取单例Signleton signleton = Signleton.getSignleton();Signleton signleton1 = Signleton.getSignleton();System.out.println(signleton.hashCode());System.out.println(signleton1.hashCode());//序列化反序列化获取对象try {ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("D:/signleton.ser"));outputStream.writeObject(signleton1);ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("D:/signleton.ser"));Signleton signleton2 = (Signleton) inputStream.readObject();System.out.println(signleton2.hashCode());} catch (IOException | ClassNotFoundException e) {// throw new RuntimeException(e);e.printStackTrace();}}

5、懒汉式DCL(推荐)

懒汉式DCL(推荐):双重检查锁定(Double-Checked Locking)是用于减少同步开销,同时保证线程安全的一种优化方法。其核心思想是:在访问共享资源时,先进行一次非同步的检查,如果未初始化,再进入同步块进行第二次检查和初始化。这样可以避免每次调用获取实例方法时都需要进行同步,从而提升性能。

java">/*** 单例设计模式:确保一个类只有一个对象实例,并提供一个全局访问点* 懒汉式:* 是否 Lazy 初始化:是* 是否多线程安全:否*/
public class Signleton implements Serializable {private static final long serialVersionUID = 1L;private static volatile Signleton signleton;private Signleton() {}public static Signleton getSignleton() {if (signleton == null) {synchronized(Signleton.class){if(signleton == null){signleton = new Signleton();}}}return signleton;}/*序列化:当一个对象被序列化时,Java 将该对象的状态写入一个字节流。反序列化:当字节流被反序列化时,Java 将创建一个新的对象实例,并将字节流中的数据填充到这个新实例中。readResolve 方法:在对象被反序列化之后,Java 会调用这个方法。如果该方法存在,返回的对象将代替默认反序列化过程中创建的新对象。*/private Object readResolve() {return signleton;}
}

6、应用场景

  • 资源共享:避免频繁的创建销毁某个对象,造成存好。比如:日志文件。
  • 控制资源:避免过多的对象产生,造成其他问题。比如网站的计数器。
  • 应用场景:
    • 日志管理器:避免频繁创建和销毁日志对象,确保日志文件只被一个实例操作,以便内容可以正确追加。
    • 网站计数器:全局唯一实例用于统计网站访问次数,避免并发更新问题。
    • Windows 回收站:整个系统运行过程中,回收站一直维护着唯一的一个实例。
    • 多线程的线程池:线程池需要方便控制池中的线程,单例模式确保线程池全局唯一。

7、单例线程池实现

java">
/*** 单例线程池 -- 应用场景*/
public class ThreadPool1 {private static ThreadPool1 threadPool;// 定义接口private ExecutorService executorService;private ThreadPool1() {executorService = new ThreadPoolExecutor(5, // 核心线程数10, // 总线程数60, TimeUnit.MILLISECONDS, // 存活时间和单位new LinkedBlockingDeque<Runnable>(),  // 用于保存等待执行的任务的队列new ThreadFactory() {  // 用于创建新线程的工厂// 定义原子操作的 int 类型。它可以在多线程环境下安全地进行自增、自减等操作而不需要同步private AtomicInteger threadNumber = new AtomicInteger(1);@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r, "CustomThreadPool-thread-" + threadNumber.getAndIncrement());// thread.setDaemon(true); // 设置为守护线程thread.setPriority(Thread.NORM_PRIORITY);return thread;}},new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略,当任务队列满了且无法再接受任务时的处理策略);}public static synchronized ThreadPool1 getThreadPool() {if (threadPool == null) {threadPool = new ThreadPool1();}return threadPool;}public void submitTask(Runnable runnable) {executorService.submit(runnable);}public void shutdown() {executorService.shutdown();}
}/*** 单例线程池测试*/@Testpublic void test2(){Runnable runnable = () -> {System.out.println(Thread.currentThread().getName() + " task is run");};// ThreadPool1.getThreadPool().submitTask(runnable);ThreadPool1 threadPool = ThreadPool1.getThreadPool();threadPool.submitTask(runnable);System.out.println(threadPool.hashCode());ThreadPool1 threadPool1 = ThreadPool1.getThreadPool();threadPool1.submitTask(runnable);System.out.println(threadPool1.hashCode());}//输出:
158199555
158199555
CustomThreadPool-thread-2 task is run
CustomThreadPool-thread-1 task is run
  • SpringBoot中的大多数容器管理的Bean都是单例的,这些bean是应用程序级别的单例,也就是说不同用户共享同一个实例。比如@RestController、@Service、@Compoment、@Configuration注解修饰的类,默认都是单例。

8、总结

  • 优点:全局唯一性、节省资源、控制共享资源、延迟初始化、易于实现。
  • 缺点:隐藏依赖关系、难以测试、线程安全问题、难以扩展、生命周期问题、违背单一职责原则。

http://www.ppmy.cn/news/1526103.html

相关文章

conda、anaconda、pip、torch、pytorch、tensorflow到底是什么东西?(转载自本人的知乎回答)

转载自本人的知乎回答&#xff08;截止2024年9月&#xff0c;1700赞同&#xff0c;2400收藏&#xff09; https://www.zhihu.com/question/566592612/answer/3063465880 如果你是一个大四的CS准研究生回去补基础课&#xff0c;假如是科班CS甚至科班EE的话那你基础也太差了。你…

相亲交友程序系统开发产品分析

相亲交友系统是一种专门为单身人士设计的社交平台&#xff0c;旨在帮助他们找到合适的伴侣。这类系统通常包括了线上和线下的多种互动方式&#xff0c;能够让参与者在舒适的环境中相识、相知。编辑&#xff1a;qawsed2466。以下是相亲交友系统的一些关键特点和优势&#xff1a;…

AI算法部署方式对比分析:哪种方案性价比最高?

随着人工智能技术的飞速发展&#xff0c;AI算法在各个领域的应用日益广泛。AI算法的部署方式直接关系到系统的性能、实时性、成本及安全性等多个方面。本文将探讨AI算法分析的三种主要部署方式&#xff1a;本地计算、边缘计算和云计算&#xff0c;并详细分析它们的优劣性。 一、…

计算机毕业设计选题推荐-推拿知识互动平台-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

基于微信小程序的宠物之家的设计与实现

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于微信小程序JavaSpringBootVueMySQL的宠物之家/宠物综合…

feign client发送Post请求,发送对象参数,服务端接收不到正确参数报错排查

记一次feignclient发送请求服务端接收不到正确参数排查 服务端代码&#xff1a; Operation(summary "Create team")PostMapping("post")RequiresPermissions("team:add")public RestResponse addTeam(Valid Team team) {this.teamService.crea…

『功能项目』切换职业技能面板【49】

我们打开上一篇48切换职业面板的项目&#xff0c; 本章要做的事情是制作第二职业法师技能面板、第三职业面板并且完成切换 双击打开Canvas进入预制体空间 复制三个技能栏面板 重命名 设置第一技能栏 设置第二职业技能栏 设置第三职业技能栏 修改脚本&#xff1a;ChangeProfess…

经纬恒润高压电池管理系统,助力新能源汽车飞速发展

随着新能源汽车行业的快速发展&#xff0c;电池管理系统作为关键技术之一&#xff0c;其重要性日益凸显。经纬恒润自主研发的高压电池管理系统&#xff08;Battery Management System&#xff0c;BMS&#xff09;&#xff0c;凭借卓越的性能与先进的技术&#xff0c;在新能源汽…

Mac清理其他文件:释放存储空间的高效指南

每个Mac用户都可能遇到存储空间不足的问题&#xff0c;尤其是当“其他”文件积累到一定体积时。在Mac上&#xff0c;“其他”文件通常包括各种系统文件、缓存、文档以及不被归类为应用程序、照片、电影或音乐的其他类型的文件。这些文件往往不易被注意&#xff0c;但逐渐占用了…

量化交易的个人见解

程序化交易在国内兴起有些年数了&#xff0c;个人以为&#xff0c;程序化交易与量化投资的关系&#xff0c;在于两者侧重点有差别。程序化交易侧重于下单的动作是机器自动执行的&#xff0c;量化投资则侧重于投资分析的过程是通过一个量化模型来实现的&#xff0c;所以量化投资…

LocalMamba: Visual State Space Model with Windowed Selective Scan 论文总结

题目&#xff1a;LocalMamba: Visual State Space Model&#xff08;视觉状态空间模型&#xff09; with Windowed Selective Scan&#xff08;窗口化的选择扫描&#xff09; 论文&#xff1a;[2403.09338] LocalMamba: Visual State Space Model with Windowed Selective Scan…

iPhone 16即将推出的5项苹果智能功能

在苹果的’Glowtime’ iPhone和Apple Watch发布会上&#xff0c;苹果宣布包括基础版和Pro版在内的iPhone 16从头开始都考虑了Apple Intelligence。这包括更新的Apple Silicon&#xff0c;改进的神经引擎&#xff0c;新硬件控制&#xff0c;以及最快下个月即将推出的操作系统改变…

深度学习驱动的车牌识别:技术演进与未来挑战

一、引言 1.1 研究背景 在当今社会&#xff0c;智能交通系统的发展日益重要&#xff0c;而车牌识别作为其关键组成部分&#xff0c;发挥着至关重要的作用。车牌识别技术广泛应用于交通管理、停车场管理、安防监控等领域。在交通管理中&#xff0c;它可以用于车辆识别、交通违…

Playwright 自动化验证码教程

Playwright 自动化点击验证码教程 在自动化测试中&#xff0c;Playwright 是一个流行的浏览器自动化工具&#xff0c;支持多种浏览器的高效操作。验证码&#xff08;如图片验证码、滑动验证码等&#xff09;是网页中常见的反自动化机制&#xff0c;常常需要特别处理。我们将介…

React学习笔记(1.0)

在使用vite创建react时&#xff0c;有一个语言选项&#xff0c;就是typescript-SWC&#xff0c;这里介绍一下SWC。 SWC&#xff1a;可扩展的Rust的平台&#xff0c;用于下一代快速开发工具&#xff0c;SWC比Babel快20倍。 简单来说&#xff0c;就是用于格式转换的&#xff0c…

Vue: 创建vue项目

目录 一.创建项目 二.项目添加 三.添加成功 一.创建项目 打开本机终端输入npm create vuelatest 二.项目添加 1. 项目名称&#xff1a; Project name: one_vue 2.是否添加TypeScript支持&#xff1a;Add TypeScript? Yes 3.是否添加JSX支持&#xff1a;Add JSX Suppor…

使用transform对html的video播放器窗口放大

核心是使用 <div class"video" style"width: 100%; height:700px;">播放容器</div>$(video).css({transform: scale(2),transform-origin: center top}); 其中 scale 表示放大倍数&#xff0c;可以是小数 transform-origin 表示位置&#…

PHP全程可视化防伪溯源一体化管理系统小程序源码

全程可视化&#xff0c;防伪溯源新篇章 —— 揭秘一体化管理系统的力量 &#x1f50d; 开篇&#xff1a;透视未来&#xff0c;从源头到终端的安心之旅 在这个信息透明化时代&#xff0c;每一件商品都承载着消费者的信任与期待。而“全程可视化防伪溯源一体化管理系统”&#x…

探索音视频SDK的双重核心:客户端与服务端的协同作用

在当今的数字化时代&#xff0c;音视频技术已成为连接人与人、人与世界的重要桥梁。从社交娱乐到在线教育&#xff0c;从远程医疗到视频会议&#xff0c;音视频技术的应用无处不在&#xff0c;极大地丰富了我们的生活方式和工作模式。本文将深入探讨音视频SDK的两大核心类别——…

k8s中的lables和matchlables的作用

statefulset中的labels和matchlables labels 是一种键值对&#xff0c;可以被附加到任何 Kubernetes 资源&#xff08;如 Pods、Services、ConfigMaps 等&#xff09;&#xff0c;用于为资源添加元数据。你可以使用 labels 对资源进行分组或标识&#xff0c;以方便管理和查询。…