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

【设计模式】创建型-单例模式

文章目录

  • 一、单例模式
  • 二、单例模式的八种实现方式
    • 2.1、饿汉式(静态常量)
    • 2.2、饿汉式(静态代码块)
    • 2.3、懒汉式(线程不安全)
    • 2.4、懒汉式(线程安全,同步方法)
    • 2.5、双重检查
    • 2.6、静态内部类
    • 2.7、枚举


一、单例模式

单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。

单例模式有三个要点:

  1. 某个类只能有一个实例
  2. 它必须自行创建这个实例
  3. 它必须自行向整个系统提供这个实例。

二、单例模式的八种实现方式

2.1、饿汉式(静态常量)

/*饿汉式(静态常量)*/
public class Singleton1 {//创建一个私有构造器,不让其他类newprivate Singleton1(){}//创建一个静态常量public static final Singleton1 INSTANCE = new Singleton1();//实例方法,方法是静态是为了通过类名调用public static Singleton1 newInstance(){return INSTANCE;}public static void main(String[] args) {Singleton1 s1 = Singleton1.newInstance();Singleton1 s2 = Singleton1.newInstance();//比较两个实例是否相等 结果:trueSystem.out.println(s1==s2);}
}

优缺点:

  • 优点:简单,类加载的时候就完成了实例化,避免了线程安全问题。
  • 缺点:如果没用到这个实例,也会实例化,浪费了内存。

2.2、饿汉式(静态代码块)

/*饿汉式(静态代码块)*/
public class Singleton2 {//创建一个私有构造器,不让其他类newprivate Singleton2(){}//定义一个静态实例public static Singleton2 instance;//静态代码块中实例化对象static {instance= new Singleton2();}//提供一个公有静态方法,放回实例化对象public static Singleton2 newInstance(){return instance;}public static void main(String[] args) {Singleton2 s1 = Singleton2.newInstance();Singleton2 s2 = Singleton2.newInstance();//比较两个实例是否相等 结果:trueSystem.out.println(s1==s2);}
}

优缺点跟上面的静态常量一样

2.3、懒汉式(线程不安全)

/** 懒汉式* 实例是在使用的时候创建,但线程不安全,会创建多个对象* */
public class Singleton3 {//定义instance静态变量private static Singleton3 instance;private Singleton3(){}//初始化方法,实现懒加载,需要时才创建对象public static Singleton3 newInstance() throws InterruptedException {//没有实例,则创建对象if (instance == null){//让线程睡一下,创造多线程进入条件Thread.sleep(20);instance = new Singleton3();}//实例化过,直接返回return instance;}public static void main(String[] args) {for (int i = 0; i < 100; i++) {//创建多线程,实现Runnable接口,重写run方法new Thread(new Runnable() {@Overridepublic void run() {try {//通过哈希码,看对象是否一样System.out.println(Singleton3.newInstance().hashCode());} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}
}

优缺点:

  • 优点:起到了懒加载效果,需要时才创建对象,但只适合在单线程下使用。
  • 缺点:在多线程情况下,一个线程 进入了if (instance == null)判断语句块,还未来得及往下执行,另一个线程又进来了,这时就产生了多个实例,造成线程不安全。

2.4、懒汉式(线程安全,同步方法)

/** 懒汉式(线程安全,加入同步方法)* */
public class Singleton4 {//定义instance静态变量private static Singleton4 instance;private Singleton4(){}//加入同步方法,保证只有一个线程进入public static synchronized Singleton4 newInstance() throws InterruptedException {//没有实例,则创建对象if (instance == null){//让线程睡一下,创造多线程进入条件Thread.sleep(20);instance = new Singleton4();}//实例化过,直接返回return instance;}public static void main(String[] args) {for (int i = 0; i < 100; i++) {//创建多线程,实现Runnable接口,重写run方法new Thread(new Runnable() {@Overridepublic void run() {try {//通过哈希码,看对象是否一样System.out.println(Singleton4.newInstance().hashCode());} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}
}

方式一是一个实例,同时锁住了空判断和创建实例,线程安全。但是这就相当于全部锁住了,就跟同步方法的效果一样,线程安全但效率很低

方式二不是一个实例,线程不安全,原因是一个线程进入了空判断,还没往下执行,另一个线程来了,其中一个线程拿到锁,往下执行创建了实例,执行完释放锁后,另一个线程也往下执行了并创建对象,两者创建的对象并不一致。

2.5、双重检查

public class Singleton6 {private static Singleton6 instance;private Singleton6(){};public static Singleton6 newInstance() throws InterruptedException {//双重检查,是单例if (instance == null){//首先判断实例是否为空,空就上锁synchronized (Singleton6.class){//上锁后,如果上面new出了个对象,此时在这判断是否为空,不为空就直接返回了,确保了只有一个实例if (instance == null){Thread.sleep(20);instance = new Singleton6();}}}return instance;}public static void main(String[] args) {for (int i = 0; i < 100; i++) {new Thread(() -> {try {System.out.println(Singleton6.newInstance().hashCode());} catch (InterruptedException e) {e.printStackTrace();}}).start();}}
}

双重检查实际上就是在懒汉式(同步代码块)的内部再添加了一个判断,这样就保证线程安全

在这里插入图片描述

2.6、静态内部类

public class Singleton7 {private Singleton7() {}//静态内部类里实例化对象,在Singleton7加载的时候,SingletonInstance内部类不加载,只在实例的时候加载private static class SingletonInstance{//静态属性,实例化对象private static final Singleton7 INSTANCE = new Singleton7();}//提供一个静态的公有方法,返回SingletonInstance类的实例public static Singleton7 newInstance(){return SingletonInstance.INSTANCE;}public static void main(String[] args) {for (int i = 0; i < 100; i++) {new Thread(()->{System.out.println(Singleton7.newInstance().hashCode());}).start();}}
}

这种方式采用了类加载的机制来保证初始化实例时只有一个线程,线程安全。静态内部类在 Singleton7 类被加载时并不会立即实例化,而是在调用 newInstance方法的时候才会实例化静态内部类,通过SingletonInstance类调用实例,从而完成 Singleton 的实例化。类的静态属性只会在第一次加载类的时候初始化,JVM 帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

2.7、枚举

package com.s.singleton;
/*** 枚举*/
public enum  Singleton8 {INSTANCE;public static void main(String[] args) {for (int i = 0; i < 100 ; i++) {new Thread(()->System.out.println(Singleton8.INSTANCE.hashCode())).start();}}
}

枚举实现是单例的,线程安全,不仅可以解决线程同步,还可以防止反序列化。《Effective Java》作者 Josh Bloch 提倡的方式。

相关文章:

【设计模式】创建型-单例模式

文章目录一、单例模式二、单例模式的八种实现方式2.1、饿汉式&#xff08;静态常量&#xff09;2.2、饿汉式&#xff08;静态代码块&#xff09;2.3、懒汉式&#xff08;线程不安全&#xff09;2.4、懒汉式&#xff08;线程安全&#xff0c;同步方法&#xff09;2.5、双重检查2…...

Python 练习 六

1、(最大数的出现)编写程序读取整数,找出它们中的最大值&#xff0c;然后计算它的出现次数。假设输入以数字0结束。假设你输入的是“352555 0";程序找出的最大数是5&#xff0c;而5的出现次数是4。(提示:维护两个变量max和 count。变量max存储的是当前最大数&#xff0c;而…...

「SQL面试题库」 No_22 员工奖金

&#x1f345; 1、专栏介绍 「SQL面试题库」是由 不是西红柿 发起&#xff0c;全员免费参与的SQL学习活动。我每天发布1道SQL面试真题&#xff0c;从简单到困难&#xff0c;涵盖所有SQL知识点&#xff0c;我敢保证只要做完这100道题&#xff0c;不仅能轻松搞定面试&#xff0…...

瞒不住了,Prefetch 就是一个大谎言

本文正在参加「金石计划」 Prefetch 是一个谎言 我们知道&#xff0c;现在的应用程序已经发展到可以拆分为多个 JavaScript包了&#xff0c;为了获得更好的用户体验&#xff0c;这些 bundle 包通常需要预获取&#xff0c;即 prefetch! 但是现在的prefetch 效果有多糟糕我想你…...

这个时候了,你还不会不知道JavaMail API吧

一、概述 1.1 简述 JavaMail API 顾名思义&#xff0c;提供给开发者处理电子邮件相关的编程接口&#xff0c;它是Sun发布的用来处理email的API&#xff0c;其提供独立于平台且与协议无关的框架来构建邮件和消息传递应用。JavaMail API 提供了一组抽象类&#xff0c;用于定义组…...

JavaScript var let区别

文章目录JavaScript var & let区别变量作用域变量提升变量重复声明全局对象属性for循环中的作用域JavaScript var & let区别 var和let都是用来声明变量的关键字。 变量作用域 var声明的变量作用域是函数作用域或全局作用域&#xff0c;而let声明的变量作用域是块级作…...

Thinkphp 6.0容器和依赖注入

本节课我们来学习一下依赖注入的用法&#xff0c;以及容器的用法。 一&#xff0e;依赖注入 1. 手册对依赖注入比较严谨的说明&#xff0c;具体如下&#xff1a; 依赖注入其实本质上是指对类的依赖通过构造器完成自动注入&#xff0c;例如在控制器架构方法和操作 方法中一旦对参…...

Type javax.servlet.http.HttpServletRequest not present

运行环境 Swagger 3.0.0、springboot 3.0.0 产生原因&#xff1a; Swagger 3.0.0不支持spring3.0.0 两个解决方案&#xff1a; 1.降低springboot版本为2.x 2.放弃Swagger&#xff0c;使用 springdoc-openapi-starter-webmvc-ui 第二种解决方案&#xff1a; <dependen…...

一键配置Ubuntu的OpenHarmony基础编译环境

一键配置Ubuntu的OpenHarmony基础编译环境 一、配置前说明 该更新源仅适用于Ubuntu以下系列 Ubuntu18.04 Ubuntu20.04 Ubuntu22.04 强烈推荐Ubuntu20.04&#xff0c;本人使用的一直都是Ubuntu20.04 wsl的配置参见 如果使用的window wsl安装&#xff0c;则关于wsl配置可参考&a…...

ASP网络求职招聘系统的设计与实现

本文主要介绍了ASP&#xff0c;数据库等相关知识&#xff0c;同时较为详尽的阐述了网络求职招聘系统的实现。本系统是使用基于HTML语言&#xff0c;嵌套JavaScript源代码的ASP编程技术来开发&#xff0c;并以IIS为服务平台实现网络求职招聘系统的构建。后台数据库选用的是ACCES…...

面试—C++《智能指针》常考点

目录 1.为什么需要智能指针 2. 内存泄漏 2.1 什么是内存泄漏&#xff0c;内存泄漏的危害 2.2 内存泄漏分类 2.3 如何检测内存泄漏 2.4如何避免内存泄漏 3.智能指针的使用及原理 3.3 std::auto_ptr 3.4 std::unique_ptr 3.5 std::shared_ptr 1.为什么需要智能指针 下…...

自动化测试方案编写思路

澄清问题: 目标&#xff1a;完成项目的自动化测试&#xff0c;设计一个方案&#xff0c;告诉领导打算怎么做&#xff1f;有哪些流程&#xff1f;花多长时间&#xff1f;需要哪些资源帮助&#xff1f;达到什么样的效果&#xff1f; 现状&#xff1a;需求分析-是个什么样的项目&a…...

【爬虫】案例04:某小说网多线程小说下载

时光轮回&#xff0c;冬去春来&#xff0c;转眼时间来到了2023年4月。天空沥沥淅淅下着小雨&#xff0c;逐渐拉上了幕布。此刻&#xff0c;正值魔都的下班高峰&#xff0c;从地铁站出来的女孩子纷纷躲到一边&#xff0c;手指飞快的划过手机屏幕&#xff0c;似乎在等待男朋友送来…...

海外独立站创业,Shopify网站如何引流

上一期给大家科普了如何快速创建自己的独立站 但往往独立站的难点在于站外引流 今天就给大家分享可以通过哪些渠道给独立站引流 - ⚡SEO排名&#xff1a;Google SEO的重要性不必多说&#xff0c;尽快注册歌账号&#xff0c;并开通Google Ad和Google Merchant Center&#…...

基于51单片机的室内湿度加湿温度声光报警智能自动控制装置设计

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;单片机湿度 获取完整无水印论文报告&#xff08;内含电路原理图和源程序代码&#xff09; 在日常生活中加湿器得到了广泛的应用&#xff0c;但是现有的加湿器都需要手工控制开启和关闭并且不具备对室内空气温湿度的监测&am…...

解决:github爆 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

目录1. 背景2. 解决办法3. 原因&#xff0c;感兴趣的可以看看1. 背景 在拉取github上一个新项目的时候爆出 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 第一反应是电脑被黑了&#xff0c;传说中的中间人攻击(题外话一下&#xff0c;其实所有的代理软件都算是中间人哦~…...

【django开发手册】如何使用select_related进行一次连表查询

前言 Django是一款Python Web框架&#xff0c;致力于充分利用Python的简洁语法和语言特性来提高Web开发的效率。其中一个强大的特性是ORM&#xff08;Object-Relational Mapping&#xff09;&#xff0c;它使开发者可以使用Python代码而不是SQL查询语言来访问数据库。ORM不仅使…...

二、MySQL 基础

二、MySQL 基础 2.1 MySQL 简介 MySQL 是一款流行的开源数据库&#xff0c;也是一个关系型数据库管理系统 在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System&#xff1a;关系数据库管理系统)应用软件之一 2.1.1 MySQL 发展历史 时间里程碑1996…...

项目中常用写法(前端)

项目中常用写法&#xff08;前端&#xff09;vue等待某个方法执行结束后&#xff0c;在执行判断js是不是undefined类型父组件传值到子组件state的值在标签中直接使用读取html&#xff0c;去掉字符串中的html标签字符串去掉中括号去掉双引号判断数组中是否包含某个值在某个ui框架…...

【面试】Java并发编程面试题

文章目录基础知识为什么要使用并发编程多线程应用场景并发编程有什么缺点并发编程三个必要因素是什么&#xff1f;在 Java 程序中怎么保证多线程的运行安全&#xff1f;并行和并发有什么区别&#xff1f;什么是多线程多线程的好处多线程的劣势&#xff1a;线程和进程区别什么是…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

Docker拉取MySQL后数据库连接失败的解决方案

在使用Docker部署MySQL时&#xff0c;拉取并启动容器后&#xff0c;有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致&#xff0c;包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因&#xff0c;并提供解决方案。 一、确认MySQL容器的运行状态 …...