单例模式

如有错误或有补充,以及任何的改进意见,请在评论区留下您的高见,同时文中给出大部分的示例

如果觉得本文写的不错,不妨点个赞,收藏一下,助力博主产生质量更高的作品

概念

单例模式(Singleton Pattern)是软件设计模式的一种,用于确保一个类只有一个实例,并提供一个全局访问点。这种模式通常用于需要频繁创建和销毁同一对象的场景,以减少系统资源的消耗和提高性能。

优缺点

优点:

实例控制:单例模式确保类只有一个实例,可以防止其他对象实例化自己的副本,从而确保所有对象都访问唯一实例。

节约资源:由于系统中只存在一个对象,可以节约系统资源,特别是在需要频繁创建和销毁对象的场景中,可以提高系统的性能。

避免对共享资源的多重占用:单例模式可以避免对共享资源的多重占用,有助于资源的集中管理和控制。

缺点:

扩展困难:由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。如果需要修改单例类的内部逻辑,则必须修改所有使用该单例的地方,不利于代码的模块化和可维护性。

职责过重:单例类通常承载了过多的职责,在一定程度上违背了“单一职责原则”。这会导致代码的复杂性增加,可读性和可维护性降低。

滥用风险:如果滥用单例模式,将一些本应该短生命周期的对象定义为单例,可能会导致内存泄漏和其他问题。例如,将数据库连接池定义为单例,可能会导致连接池溢出或资源耗尽。

状态丢失:在某些情况下,如果实例化的对象长时间不被利用,系统可能会将其视为垃圾回收,导致对象状态的丢失。

使用场景

比如Spring的IOC容器非懒加载的Bean,网页浏览计数等。

实现方式

饿汉式

饿汉式是在类加载时即实例化单例对象的一种方式。在类加载时,饿汉式单例实例就会被创建。这种方式可以确保在程序启动时就能使用单例对象,但是如果在整个应用程序中并不需要使用该单例对象,则会造成资源浪费

示例

SingletonClass1.java

// 饿汉式
public class SingletonClass1 {// 创建唯一对象private static SingletonClass1 instance = new SingletonClass1();// 避免实例化private SingletonClass1() {}// 获取唯一对象public static SingletonClass1 getInstance() {return instance;}public void hello () {System.out.println("This is SingletonClass1");}
}

Main.java

public class Main {public static void main(String[] args) {SingletonClass1.getInstance().hello();}
}

懒汉式

懒汉式是在需要使用单例对象时才进行实例化的一种方式。在类加载时,懒汉式单例实例并不会被创建,而是在第一次调用时才创建。这种方式可以避免不必要的资源浪费,但在多线程环境下可能会出现问题。在懒汉式实现中,需要将单例的实例化放在一个公共的静态方法中,以确保线程安全

// 懒汉式
public class SingletonClass2 {// 初始不加载private static SingletonClass2 instance = null;// 避免实例化private SingletonClass2() {}// 获取对象的方法public static synchronized SingletonClass2 getInstance() {if (instance == null) {instance = new SingletonClass2();}return instance;}public void hello() {System.out.println("This is SingletonClass2");}
}

Main.java

public class Main {public static void main(String[] args) {SingletonClass2.getInstance().hello();}
}

以上的懒汉式实现效率较低,每次都要通过synchronized,效率较低

以下是通过双重锁检查机制来使其更加高效的例子:

双重检查锁定(Double-Checked Locking)是一种在多线程环境下使用的同步机制,主要用于实现单例模式。其基本原理是在第一次检查时验证实例是否已经创建,如果已经创建则直接返回实例,不需要进行后续的同步操作。如果实例尚未创建,则进入同步块,在同步块内部进行第二次检查,以确保只有一个线程创建实例。双重检查锁定的目的是在尽量减少同步操作的情况下,保证在多线程环境中只有一个实例被创建,这样可以避免性能下降,同时保证线程安全。需要注意的是,在使用双重检查锁定时,需要使用volatile关键字修饰实例变量,以确保其可见性,避免指令重排序导致的问题。此外,由于不同版本的JVM和编译器对指令重排序的处理方式可能不同,因此在使用双重检查锁定时,需要仔细考虑各种因素,确保其正确性和可靠性。

双重锁检查机制效率更高的原因主要有以下几点:

减少同步锁的调用次数:在懒汉式单例模式中,如果不使用双重锁检查机制,每次调用 getInstance() 方法时都需要获取同步锁,这会导致性能下降。而双重锁检查机制通过第一次检查减少了获取同步锁的次数,只有在实例未创建的情况下才会进入同步块,从而提高了性能。

提升并发度,降低开销:由于双重锁检查机制在第一次检查时只进行了简单的 null 检查,而这个操作是非常快速的,开销也比较小,因此它可以快速地释放同步锁,让其他线程有机会进入同步块,从而提高了并发度。同时也可以降低开销,提高性能。

SingletonClass2Plus.java

// 懒汉式Plus
public class SingletonClass2Plus {// 初始不加载private static volatile SingletonClass2Plus instance = null;// 避免实例化private SingletonClass2Plus() {}public static SingletonClass2Plus getInstance() {// 第一次检查if (instance == null) {synchronized (SingletonClass2Plus.class) {// 第二次检查if (instance == null) {instance = new SingletonClass2Plus();}}}return instance;}public void hello() {System.out.println("This is SingletonClass2Plus");}
}

Main.java

public class Main {public static void main(String[] args) {SingletonClass2Plus.getInstance().hello();}
}

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

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

相关文章

scienceplots绘图浅尝

前言 科研写作中,黑压压的文字里面如果能有一些优美的图片无疑会给论文增色不少,绘图的工具有很多,常用的有Excel、Python、Matlab等,Matlab在绘图方面相较于Python有一种更加原生的科研风,而且可视化编辑图例、坐标轴…

Maltab 输出矢量图

来源 MATLAB 仿真完,想把结果导出矢量图,放 latex 中写论文 方法 指定 render 方式为 vector print(Fig, FileName,-dpdf,-r0, -vector)或者指定 Fig 的 render 为 painters Fig.Renderer painters; 其他方法 参考 print 函数,可以输…

ManticoreSearch-(安装配置,集群搭建)-学习总结

ManticoreSearch-(安装配置)-学习总结 基础概念安装搭建集群搭建(基于K8S) 原文地址 https://blog.csdn.net/liuyij3430448/article/details/135955025 基础概念 Manticore Search是一个专门为搜索设计的多存储数据库,具有强大的全文搜索功能,适用于…

Python入门指北十七

Python中如何实现继承和多态? 在Python中,继承和多态的实现方式与其他面向对象编程语言类似。 继承 Python使用class关键字来定义类,并通过冒号(:)来指定父类。例如: class Animal:def __init__(self, …

java的单例设计模式

1什么是单例设计模式: 所谓类得单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法; 2.单例模式有两种方式: 2.1饿汉式 如…

【SparkML系列3】特征提取器TF-IDF、Word2Vec和CountVectorizer

本节介绍了用于处理特征的算法,大致可以分为以下几组: 提取(Extraction):从“原始”数据中提取特征。转换(Transformation):缩放、转换或修改特征。选择(Selection&…

15.Golang中的反射机制及应用

目录 概述实践基本应用复杂应用 结束 概述 Golang中的反射用法还是比较简单的 reflect.TypeOf(arg)reflect.ValueOf(arg) 实践 基本应用 package mainimport ("fmt""reflect" )func reflectNum(arg interface{}) {fmt.Println("type ", re…

网络异常案例三_RST

问题现象 在做功能测试的时候,经常看到设备离线的消息(MQTT遗嘱)。 在终端连接的网络设备上抓包分析,看到终端设备发起大量的RST请求。 151这个设备,7min,重置断开了8个TCP连接(mqtt连接&#…

Fiber

在React中,Fiber是一个核心架构,它是React 16及后续版本中用于处理和调度组件更新的一种机制。React Fiber的核心目的是改进React对复杂应用状态更新的处理方式,特别是为了更好地支持如动画、布局偏移等高性能需求场景,同时提供了…

理解部署描述符的元素

理解部署描述符的元素 部署描述符是文件名为web.xml的XML文件,其包含了Web应用程序的配置信息。每个Web应用程序都有一个web.xml文件。web.xml文件的元素可用于指定servlet的初始化参数、不同文件的MIME类型、侦听器类,以及将URL模式映射到servlet上。一…

2024年,AI 掀起数据与分析市场的新风暴

2024 年伊始,Kyligence 联合创始人兼 CEO 韩卿在其公司内部的飞书订阅号发表了多篇 Rethink Data & Analytics 的内部信,分享了对数据与分析行业的一些战略思考,尤其是 AI 带来的各种变化和革命,是如何深刻地影响这个行业乃至…

vue中nextTick()

在 Vue.js 中&#xff0c;nextTick() 是一个非常有用的方法&#xff0c;用于在下一个 DOM 更新循环结束后执行延迟回调。这在你需要读取或写入刚刚更新的 DOM 时非常有用。 下面是一个简单的示例代码&#xff0c;用于解析 nextTick() 的用法&#xff1a; <template> &…

防御挂马攻击:从防御到清除的最佳实践

挂马攻击&#xff0c;也称为马式攻击&#xff08;Horse Attack&#xff09;&#xff0c;是一种常见的网络攻击手段。攻击者通过在目标服务器或网站中植入恶意程序&#xff0c;以获取系统权限或窃取敏感信息。为了应对这种威胁&#xff0c;本文将重点介绍防御挂马攻击的最佳实践…

【SparkML系列1】相关性、卡方检验和概述器实现

Correlation(相关性) 计算两组数据之间的相关性在统计学中是一种常见的操作。在spark.ml中&#xff0c;我们提供了计算多组数据之间成对相关性的灵活性。目前支持的相关性方法是皮尔逊&#xff08;Pearson&#xff09;相关系数和斯皮尔曼&#xff08;Spearman&#xff09;相关…

VTK 交互事件

学习笔记&#xff1a;VTK 交互事件 1. 定义 VTK&#xff08;Visualization Toolkit&#xff09;中的交互事件是与用户交互操作相关的事件&#xff0c;例如鼠标移动、按键按下、小部件交互等。这些事件允许程序捕捉用户的输入&#xff0c;从而实现交互式的可视化体验。 2. 参…

AI项目落地成功因素:数据和机器学习模型的选择

构建机器学习模型时&#xff0c;需要考虑几个关键要素&#xff1a;计算能力、算法和数据。公司往往会将大部分资源集中于开发正确的、无偏见的算法&#xff0c;并加大对计算能力的投入&#xff0c;而在运行模型前&#xff0c;数据通常靠边站或完全被抛诸脑后。 如果数据被遗忘&…

消息中间件(MQ)对比:RabbitMQ、Kafka、ActiveMQ 和 RocketMQ

前言 在构建分布式系统时&#xff0c;选择适合的消息中间件是至关重要的决策。RabbitMQ、Kafka、ActiveMQ 和 RocketMQ 是当前流行的消息中间件之一&#xff0c;它们各自具有独特的特点和适用场景。本文将对这四种消息中间件进行综合比较&#xff0c;帮助您在项目中作出明智的…

C语言——动态内存管理(经典例题)

题1、 为什么会崩溃呢&#xff1f;&#x1f914;&#x1f914;&#x1f914; #include <stdio.h> #include <stdlib.h> #include <string.h>void GetMemory(char** p) {*p (char*)malloc(100); } void Test(void) {char* str NULL;GetMemory(&str);str…

SQL DISTINCT 用法总结

SQL DISTINCT 用法总结 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;今天我们将深入研究 SQL 中的 DISTINCT 关键字。DISTINCT 是一项非常有用的功能&#xff0c;用于从查询结果中消除重复的行&#xff0c;让我们一起学习其基本…

QT 组装json,广播发送

QUdpSocket *udpSocket; udpSocket new QUdpSocket(); //创建一个QUdpSocket QByteArray byteArray; QJsonObject rectJson; rectJson.insert("NW1", NW1); rectJson.insert("NW2", NW2); rectJson.insert("NW3", NW3); rectJson.insert(&quo…