【设计模式】单例模式(懒汉和饿汉模式详解)

news2025/1/16 17:45:19

目录

1.设计模式是什么?

2.单例模式

1.概念:

2.如何设计一个单例

1.口头约定(不靠谱)

2.使用编程语言的特性来处理

3.使用"饿汉模式"设计单例

1.详细步骤

2.完整代码

 4.使用"饿汉模式"设计单例

1.详细步骤

2.完整代码

4. "饿汉模式"和"懒汉模式"的区别

 


 

1.设计模式是什么?

设计模式就是厉害的程序员根据以往的设计经验,总结出来的一套方法,类似于棋谱

2.单例模式

1.概念:

单例模式就是一种设计模式

单例在全局范围内只有一个实例化对象

例如在java通过JDBC连接数据库是使用的DateSource类,在这个类中定义了数据库的用户名,密码,连接串,定义好了以上的属性就可以通过DateSource的实例化对象获取数据路的链接

2.如何设计一个单例

1.口头约定(不靠谱)

对外提供一个方法,要求大家使用的时候,通过这个方法来获取

不能保证每个人都遵守规定,所以不采用

2.使用编程语言的特性来处理

首先我们思考一下,在Java中,哪些对象是唯一的?

1.class对象类对象,比如String.class

2.用static修饰的变量是类的成员变量

所有的实例对象中,访问的都是同一个成员变量

所以,通过类对象与static配合就可以实现单例的目的

3.使用"饿汉模式"设计单例

类似于这种随着类的加载一起完成初始化的方式,称之为"饿汉模式"

"饿汉模式"书写简单,不容易出错

1.详细步骤

1.我们让其在类加载的时候完成初始化,那么所有对象之间共享这个实例

c7d552804137499a9c6a0834d95bb94c.png

2.既然是单例,全局唯一的对象,那么就不能通过new去获取新对象

将构造方法私有化,就可以避免外部new这个类的新对象

da8db1aa1ab444849a95bf4079ddd9ff.png

3.我们对外部提供一个获取对象的方法,每次调用返回的都是同一个实例对象

将方法用ststic修饰,使其可以通过类名直接调用

f3544abeb3524c32a60cd685e3d17b68.png

2.完整代码

public class Singleton {
    public static Singleton instance = new Singleton();

    private Singleton(){};

    public static Singleton getinstance() {
        return instance;
    }
}

 4.使用"饿汉模式"设计单例

为了避免程序启动的时候浪费过多的系统资源,我们可以暂时先不初始化这个实例对象,等到程序使用的时候在对他进行初始化

1.详细步骤

最初我们并不对其进行初始化,而是在使用的时候进行初始化

8fb148ff6b354efd9e38f415d60feac4.png

但此时出现了一个问题,在多线程下去获取单例对象,出现了两个以上的实例化对象,这并不符合单例模式,说明我们的代码造成了线程不安全的现象

分析造成线程不安全的原因

8e1881351ede454799bfd3f19308a29a.png

没有保证初始化实例对象操作的原子性 

为了解决这个问题,我们给初始化的代码上锁

f4b4dbe5a4614b20ab0c8d29a5be741e.png

目前看来似乎解决了问题

但是出现了一个更严重的问题,初始化实例对象这部分代码块,在整个程序的调用过程中,只需要执行一次就足以,但是按照我们现在的写法,只要外部调用了getinstance()方法,那么所有的线程都需要参与锁竞争,都必须停下来一个个地执行,然而锁竞争是非常耗费资源的,这势必会造成大量的资源浪费,这与我们的预期也是不符的

这里我们需要知道一个知识

用户态与内核态

1a2227d139dc4d0eabded4f8658252bc.png

 为了避免过度消耗系统资源,我们可以在加一层判断

双重检查锁,这两层if语句判断的目的是不一样的

7a34745d59444027a4f8324f23fc1374.png

 第一个if语句用来判断实例对象是否是还未进行初始化,若还未初始化,因为只能初始化一次,所以加锁,只允许一个线程去执行初始化操作,其余线程等待,

第二个if语句用来判断被第一条if语句遗漏的线程,此时这个线程已经获取到instance为空,但却并未争抢到执行机会,使得其他线程先一步初始化成功对象实例,此时当这个线程终于争抢到CPU执行机会时,我们需要对它重新判断,因为此时实例对象已初始化完成,不需要再次进行初始化

到现在我们通过synchronized关键字解决了原子性,内存可见性,那么有序性我们又该如何保证呢?

那么就需要给共享变量加volatile关键字

有人不理解,上面测试明明已经是同一个实例化对象了,为什么我们还要多此一举呢?

让我们用时间线来展开说明

a07c71d0480349af951983188103d9ef.png

2.完整代码

public class Singleton01 {
    private static Singleton01 instanse = null;

    private Singleton01(){};

    public static Singleton01 getinstance() {
        if (instanse == null) {
            synchronized (Singleton01.class) {
                if(instanse == null) {
                    instanse = new Singleton01();
                }
            }
        }
        return instanse;
    }
}

4. "饿汉模式"和"懒汉模式"的区别

1.工作中可以使用 "饿汉模式",因为书写简单,不容易出错

2."饿汉模式"在程序加载的时候一起完成初始化,但由于计算机资源有限,为了节约资源,可以使用"懒汉模式"加载

3.懒汉模式在多线程情况下可能会出现不安全的问题

4.我们可以使用synchronized包裹初始化的代码块

5.但初始化实例对象的代码块只执行一次,后续线程在调用getinstance()方法时,依然会产生锁竞争,频繁的进行用户态与内核态之间的切换,非常的耗费计算机资源

6.使用双重检查锁,在最外层加一个非空校验,避免无用的锁竞争

7.此时还存有有序性的隐患,若计算机对指令重排序,可能会带来不可预计的错误

8.synchronized解决了原子性,内存可见性,但是解决不了有序性,所以给共享变量加一个volatile修饰,禁止计算机对指令的重排序

 

 

 

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

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

相关文章

php+vue在线课程教育学习考试系统864t7

运行环境:phpstudy/wamp/xammp等 开发语言:php 后端框架:Thinkphp5 前端框架:vue.js 服务器:apache 数据库:mysql 数据库工具:Navicat/phpmyadmin功能要求:可以实现首页、个人中心、学生管理、名…

嵌入式软考备考_7 系统开发过程和项目管理

系统开发过程和项目管理 开发模型 把开发过程分成一些阶段。 瀑布模型:SDLC。缺陷在于最开始需求要明确,但是开发周期很难不变动。 因此改进: 原型:一个demo。 快速原型模型:抛弃模型,一旦获取到了用户需…

unity 基本寻径

一、实现效果:敌人追逐玩家,自动躲避障碍物 二、游戏框架 Plane:平面,是玩家和敌人可以行走的区域 Player:玩家,可以在平面上移动,绕开障碍物 Enemy:敌人,可以追逐玩家…

红外遥控且自动避障的嵌入式智能小车系统

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 本次实验使用树莓派作为开发平台,AlphaBot 作为开发载体,Python 作为开发语言,开发一种基于红外线遥控控制的、可自动避障的嵌入式智能小车系统。 智能系统中的嵌入式应用 实验目的 嵌入式…

MySQL双写缓冲区(Doublewrite Buffer)

本文已收录至Github,推荐阅读 👉 Java随想录 文章目录 摘要为什么需要Doublewrite BufferDoublewrite Buffer原理Doublewrite Buffer相关参数总结 摘要 InnoDB是MySQL中一种常用的事务性存储引擎,它具有很多优秀的特性。其中,Dou…

pip的常用操作命令

1. 忽略已安装的库(以llvmlite为例) pip install xxx --ignore-installed llvmlite 2. 错误 - AttributeError: int object has no attribute endswith 解决方案: 常见原因因为使用的pip为pip2,可以使用 pip -V 查看pip版本&a…

springboot+vue校园博客系统(源码+文档)

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的校园博客系统。项目源码以及部署相关请联系风歌,文末附上联系信息 。 💕💕作者:风歌&a…

AD 域环镜 本地管理员密码解决方案(LAPS)部署

前言: 我们知道window10装好后,默认本地管理员账号Administrator是关闭的,通过组策略启用本地管理员账号没有问题,具体方法在下面,但是由于微软《MS14-025:组策略首选项中的漏洞可能允许特权提升&#xff…

06-引入SpringSecurity 尚筹网

SpringSecurity 框架用法简介 用户登录系统时我们协助 SpringSecurity 把用户对应的角色、权限组装好,同时把各个资源所要求的权限信息设定好,剩下的“登录验证”、“权限验证”等等工作都交给SpringSecurity。 权限管理过程中的相关概念 主体 英文单…

【源码解析】Spring Cloud Gateway使用RedisRateLimiter实现限流

实现方案 在gateway项目中引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId> </dependency><dependency><groupId>org.springframework.boot</g…

3BHB003154R0101确定每个控制器将如何知道设备地址、识别发给它的消息

3BHB003154R0101确定每个控制器将如何知道设备地址、识别发给它的消息 DNP3 协议用于各种 SCADA 系统组件之间的通信。这些系统组件包括 SCADA 主站或HMI、远程终端单元和智能电子设备。SCADA 系统的操作员可以在其操作中监控 DNP3 协议&#xff0c;以提高系统可靠性。这将通过…

java版深圳 工程管理系统软件 自主研发,工程行业适用 软件源码

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目显示…

Redis 常见缓存问题与解决方案

文章目录 1. 缓存穿透解决方法 2. 缓存击穿解决方法 3. 缓存雪崩解决方法 在 redis 的应用场景中&#xff0c;需要考虑缓存在某些场景下可能出现的问题&#xff1a; 缓存穿透 缓存击穿 缓存雪崩 以下缓存问题的讨论都是基于以下应用架构讨论的&#xff1a; 1. 缓存穿透 对应…

Python 中的字典顺序

文章目录 Python 中的字典顺序在 Python 中将数字列表按词典顺序排序 我们将介绍 Python 中的字典顺序。 我们还将通过示例讨论实现词典顺序的不同方法。 Python 中的字典顺序 在数学中&#xff0c;词典顺序或词典顺序是对按字母顺序排列的元素列表或元素数组进行排序的过程。…

Java学习之Swing图形界面

Java提供的Swing组件众多&#xff0c;下面列举其中的几种&#xff0c;本章主要讲解顶层容器&#xff0c;其余容器在下面几章会做讲解。 1、顶层容器 1&#xff09;顶层容器就是不包含在其他容器中的容器&#xff0c;Swing中常见的顶层容器有JFrame&#xff0c;JFrame被称为窗口…

分享78个C 源码,总有一款适合您

C 源码 分享78个C 源码&#xff0c;总有一款适合您 源码下载链接&#xff1a;https://pan.baidu.com/s/1_vslGj8XQUGbUhQFnKZg4g?pwdoe87 提取码&#xff1a;oe87 OpenCV计算机视觉库 v4.7.0 OpenCV计算机视觉库 v3.4.19 Photoflare图像编辑器v1.6.12 开源向量数据库mil…

Lecture 13(Extra Material):PPO

On-policy v.s.Off-policy On-policy: The agent learned and the agent interacting with the environment is the same.Off-policy: The agent learned and the agent interacting with the environment is different. Issue of Importance Sampling: 尽管q可以是任意的&am…

day43—编程题

文章目录 1.第一题1.1题目1.2思路1.3解题 2.第二题2.1题目2.2思路2.3解题 1.第一题 1.1题目 描述&#xff1a; 输入两个整数 n 和 m&#xff0c;从数列1&#xff0c;2&#xff0c;3…n 中随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来 输入描述: 每个测试输入包…

Java 基础进阶篇(十二)—— Stream 流常用方法总结

文章目录 一、Stream流概述二、获取Stream流2.1 集合获取 Stream 流2.2 数组获取 Stream 流 三、中间方法四、终结方法五、Stream流的综合应用六、收集Stream流 一、Stream流概述 Stream 流是在 Java8 中&#xff0c;得益于 Lambda 所带来的函数式编程&#xff0c; 引入了一个…

前端技术——css

1.CSS的引入 【1】为什么要学习CSS? 如果只用HEML画页面的话--->这个页面就是页面上需要的元素罗列起来&#xff0c;但是页面效果很差&#xff0c;不好看&#xff0c;为了让页面好看&#xff0c;为了修饰页面。所以我们需要用到CSS。 CSS的作用&#xff1a;修饰HTML页面…