23种设计模式之创建型模式 - 单例模式

文章目录

  • 一、单例模式
    • 1.1单例模式定义
    • 1.2 单例模式的特点
  • 二、实现单例模式的方式
    • 2.1 饿汉式
    • 2.2 懒汉式
    • 2.3 双重检查锁:
    • 2.4 静态内部类
    • 2.5 枚举实现(防止反射攻击):

一、单例模式

1.1单例模式定义

单例模式确保系统中某个类只有一个实例,并提供一个访问它的全局访问点。主要解决一个全局使用的类频繁地创建与销毁,控制实例数目,节省系统资源。

1.2 单例模式的特点

  • 单例类只能有一个实例
  • 单例类必须自己创建自己的唯一实例
  • 单例类必须给所有其他对象提供这一实例
  • 单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性

单例的四大原则:

  • 构造私有
  • 以静态方法或者枚举返回实例
  • 确保实例只有一个,尤其是多线程环境
  • 确保反序列换时不会重新构建对象

二、实现单例模式的方式

2.1 饿汉式

饿汉式单例在类加载初始化时就创建好一个静态的对象供外部使用,除非系统重启,这个对象不会改变,所以本身就是线程安全的。
Singleton 通过将构造方法限定为 private 避免了类在外部被实例化,在同一个虚拟机范围内,Singleton 的唯一实例只能通过 getInstance()方法访问。(事实上,通过 Java 反射机制是能够实例化构造方法为 private 的类的,会使 Java单例实现失效)

/*** @Author huang.bX* @Date 2021/7/21*/
public class SingletonTest01 {public static void main(String[] args) {Hungry instance = Hungry.getInstance();Hungry instance1 = Hungry.getInstance();Hungry instance2 = Hungry.getInstance();System.out.println(instance.getClass());System.out.println(instance1.getClass());System.out.println(instance2.getClass());}
}//饿汉式
class Hungry {//1构造器私有化,外部不能直接newprivate Hungry() {}//2本类的内部创建实例private final static Hungry hungry = new Hungry();//提供一个全局访问点共有的静态方法 返回实例对象public static Hungry getInstance(){return hungry;}
}

在这里插入图片描述

2.2 懒汉式

该示例虽然用延迟加载方式实现了懒汉式单例,但在多线程环境下会产生多个 Singleton 对象;

/*** @Author huang.bX* @Date 2021/7/21*/
public class SingletonTest03 implements Runnable {@Overridepublic void run(){for (int i=1;i<1000;i++){LazyMan lazyMan=LazyMan.getInstance();System.out.println(lazyMan.hashCode());}}public static void main(String[] args) {/**   LazyMan instance1 = LazyMan.getInstance();*   LazyMan instance2 = LazyMan.getInstance();*  System.out.println(instance1.hashCode()==instance2.hashCode());*/new Thread(new SingletonTest03()).start();new Thread(new SingletonTest03()).start();new Thread(new SingletonTest03()).start();}
}class LazyMan{private LazyMan(){}private static LazyMan lazyMan;//public static LazyMan getInstance()线程不安全public static synchronized LazyMan getInstance(){if (lazyMan==null){lazyMan = new LazyMan();}return lazyMan;}
}

在这里插入图片描述

2.3 双重检查锁:

使用双重检查锁进一步做了优化,可以避免整个方法被锁,只对需要锁的代码部分加锁,可以提高执行效率。

/*** @Author huang.bX* @Date 2021/7/21*/
public class SingletonTest05 {public static void main(String[] args) {DoubleLock instance1 = DoubleLock.getInstance();DoubleLock instance2 = DoubleLock.getInstance();System.out.println(instance1.hashCode()==instance2.hashCode());}
}class DoubleLock{private static volatile DoubleLock doubleLock;private DoubleLock(){}public static DoubleLock getInstance(){if (doubleLock==null){synchronized (DoubleLock.class){if (doubleLock==null){doubleLock = new DoubleLock();}}}return doubleLock;}
}

在这里插入图片描述

2.4 静态内部类

这种方式引入了一个内部静态类(static class),静态内部类只有在调用时才会加载,它保证了 Singleton 实例的延迟初始化,又保证了实例的唯一性。它把 singleton 的实例化操作放到一个静态内部类中,在第一次调用 getInstance() 方法时,JVM 才会去加载 InnerObject 类,同时初始hsingleton 实例,所以能让 getInstance() 方法线程安全。特点是:即能延迟加载,也能保证线程安全。静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。

/*** @Author huang.bX* @Date 2021/7/21*/
public class SingletonTest06 {public static void main(String[] args) {StaticInClass instance1 = StaticInClass.getInstance();StaticInClass instance2= StaticInClass.getInstance();System.out.println(instance1.hashCode()==instance2.hashCode());}
}class StaticInClass{private static volatile StaticInClass staticInClass;//构造器私有化private StaticInClass(){}//定义一个静态内部类,该类中有一个静态属性private static class Inner{private static final StaticInClass INSTANCE = new StaticInClass();}public static synchronized StaticInClass getInstance(){return Inner.INSTANCE;}}

在这里插入图片描述

2.5 枚举实现(防止反射攻击):

事实上,通过 Java 反射机制是能够实例化构造方法为 private 的类的。这也就是我们现在需要引入的枚举单例模式。

/*** @Author huang.bX* @Date 2021/7/21*/
public class SingletonTest07 {public static void main(String[] args) {Singleton instance1 = Singleton.INSTANCE;Singleton instance2 = Singleton.INSTANCE;System.out.println(instance1.hashCode());System.out.println(instance2.hashCode());System.out.println(instance2.hashCode()==instance1.hashCode());System.out.println(instance1.getClass());System.out.println(instance2.getClass());System.out.println(instance1.getDeclaringClass());}
}enum Singleton{INSTANCE;//属性public void say(){System.out.println("ok!");}
}

在这里插入图片描述

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

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

相关文章

蓝桥杯刷题之路径之谜

题目来源 路径之谜 不愧是国赛的题目 题意 题目中会给你两个数组&#xff0c;我这里是分别用row和col来表示 每走一步&#xff0c;往左边和上边射一箭&#xff0c;走到终点的时候row数组和col数组中的值必须全部等于0这个注意哈&#xff0c;看题目看了半天&#xff0c;因为…

libVLC 视频抓图

Windows操作系统提供了多种便捷的截图方式&#xff0c;常见的有以下几种&#xff1a; 全屏截图&#xff1a;通过按下PrtSc键&#xff08;Print Screen&#xff09;&#xff0c;可以截取整个屏幕的内容。截取的图像会保存在剪贴板中&#xff0c;可以通过CtrlV粘贴到图片编辑工具…

vivado 使用远程主机和计算群集

使用远程主机和计算群集 概述 AMD Vivado™集成设计环境&#xff08;IDE&#xff09;支持同时并行合成和实现的执行在多个Linux主机上运行。你可以做到这一点通过配置单个主机或指定要在其上启动作业的命令手动执行现有的计算集群。目前&#xff0c;Linux是Vivado唯一支持远程主…

【Ollama】AI大模型本地部署

Ollama Ollama轻量级、可扩展的框架&#xff0c;用于在本地机器上构建和运行大型语言模型&#xff08;LLM&#xff09;。提供了一个简单的API来创建、运行和管理模型&#xff0c;以及一个预构建模型库&#xff0c;可以轻松用于各种应用程序。 明显优势&#xff1a;易于使用、…

python Flask扩展:如何查找高效开发的第三方模块(库/插件)

如何找到扩展以及使用扩展的文档 一、背景二、如何寻找框架的扩展&#xff1f;三、找到想要的扩展四、找到使用扩展的文档五、项目中实战扩展 一、背景 刚入门python的flask的框架&#xff0c;跟着文档学习了一些以后&#xff0c;想着其实在项目开发中&#xff0c;经常会用到发…

Python字符串操作

1.len(返回字符串的长度): text "Hello, world!" print(len(text)) # Output: 132.find(查找字符串在某字符串中是否包含): text "Hello, world!" print(text.find("world")) # Output: 7 3.index(查找字符串在某字符串中是否包含): tex…

图书推荐|Django+Vue.js商城项目实战

一线资深架构师 凝聚近十年大型系统开发经验 倾力打造 双色印刷 适合&#xff1a;项目演练求职应聘技术提升 全新&#xff1a;Django 4.x与Vue.js 3.x全栈技术 易学&#xff1a;娓娓道来图示指引原理剖析步骤解说代码详注 真实企业级项目技术细节完整揭秘&#xff0c;照着做就…

【JavaWeb】Day23.maven——依赖管理

依赖管理 一.依赖配置 依赖&#xff1a;指当前项目运行所需要的jar包。一个项目中可以引入多个依赖。 例如&#xff1a;在当前工程中&#xff0c;我们需要用到logback来记录日志&#xff0c;此时就可以在maven工程的pom.xml文件中&#xff0c;引入logback的依赖。具体步骤如…

开源大数据集群部署(十八)Hive 安装部署

作者&#xff1a;櫰木 1 创建hive Kerberos主体 bash /root/bigdata/getkeytabs.sh /etc/security/keytab/hive.keytab hive2 安装 在hd1.dtstack.com主机root权限下操作&#xff1a; 解压包 [roothd3.dtstack.com software]# tar -zxvf apache-hive-3.1.2-bin.tar.gz -C …

WPF 命名空间解释

在C#中有命名空间的概念&#xff0c;我们可以使用using引入&#xff0c;就可以使用其中的类&#xff0c;在xaml中&#xff0c;也同样有命名空间&#xff0c;在window标签中用xmlns声明的这几行&#xff0c;这就是本页面引入的命名空间。 一般的情况下&#xff0c;我们引入命名空…

钡铼技术R40工业4G路由器为户外广告牌智能控制系统提供无线网络

钡铼技术R40工业4G路由器在户外广告牌智能控制系统中的应用&#xff0c;为广告行业带来了革命性的变革。作为一种先进的无线通信设备&#xff0c;R40工业4G路由器通过其稳定的信号传输和强大的网络连接能力&#xff0c;为户外广告牌的智能控制系统提供了可靠的无线网络支持&…

汇编语言学习记录 01

目录 VScode配置调试环境 Debug的主要命令 简单写个Hello World VScode配置调试环境 没有IDE真的蛮难受的 安装插件TASM/MASM 右键扩展设置&#xff0c;选择Assembler&#xff1a;MASM 右键调试即可开始 Debug的主要命令 R-查看和修改寄存器 D-查看内存单元 E-修改内…

docker学习笔记 四-----docker基本使用方法

基础命令奉上&#xff1a; 1、docker命令查询方法 docker --help 获取docker命令帮助 docker search --help 查询docker 子命令search的帮助 2、查询镜像 查询镜像 docker search 192.168.206.100:5000/mysql 查询指定服务器指定镜像 docker search mysql …

树与二叉树的应用试题解析

01&#xff0e;在有n个叶结点的哈夫曼树中&#xff0c;非叶结点的总数是( A ). A. n-1 B. n C. 2n-1 D.2n 02.给定整数集合{3,5,6,9,12}&#xff0c;与之对应的哈夫曼树是( D…

OpenCV模块熟悉:点云处理相关

1. 显示--VIZ 曾经基于PCL 做过不少点云相关的开发&#xff0c;采样VTK进行有点云显示。后来基于OpenCV做了不少三维重建工作&#xff0c;总是将点云保存下来&#xff0c;然后借助CloudCompare等查看结果。如果能够将VIZ编译进来&#xff0c;预计会提升开发速度。 …

队列+宽搜例题讲解!

429. N 叉树的层序遍历 题目解析&#xff1a; 根据题目分析&#xff0c;可以看出题目要我们求的是N叉数的层序遍历&#xff0c;就是把每层的放在一块&#xff0c;最后把每层都输出出来即可&#xff01; 算法分析&#xff1a; 我们可以利用队列先进先出的特性进行求解&#x…

Machine Learning机器学习之K近邻算法(K-Nearest Neighbors,KNN)

目录 前言 背景介绍&#xff1a; 思想&#xff1a; 原理&#xff1a; KNN算法关键问题 一、构建KNN算法 总结&#xff1a; 博主介绍&#xff1a;✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神&#xff0c;答疑解惑、坚持优质作品共…

基于大语言模型的云故障根因分析|顶会EuroSys24论文

*马明华 微软主管研究员 2021年CCF国际AIOps挑战赛程序委员会主席&#xff08;第四届&#xff09; 2021年博士毕业于清华大学&#xff0c;2020年在佐治亚理工学院做访问学者。主要研究方向是智能运维&#xff08;AIOps&#xff09;、软件可靠性。近年来在ICSE、FSE、ATC、EuroS…

人脸68关键点与K210疲劳检测

目录 人脸68关键点检测 检测闭眼睁眼 双眼关键点检测 计算眼睛的闭合程度&#xff1a; 原理: 设置阈值进行判断 实时监测和更新 拓展&#xff1a;通过判断上下眼皮重合程度去判断是否闭眼 检测嘴巴是否闭合 提取嘴唇上下轮廓的关键点 计算嘴唇上下轮廓关键点之间的距…

喜讯!聚铭网络荣获《日志分类方法及系统》发明专利

近日&#xff0c;聚铭网络又喜获一项殊荣&#xff0c;其申报的《日志分类方法及系统》发明专利成功获得国家知识产权局的授权&#xff0c;正式荣获国家发明专利证书。 在信息化时代&#xff0c;网络安全问题日益凸显&#xff0c;日志分析作为保障网络安全的重要手段&#xff…