【多线程案例】单例模式(懒汉模式和饿汉模式)

文章目录

    • 1. 什么是单例模式?
    • 2. 立即加载/“饿汉模式”
    • 3. 延时加载/“懒汉模式”
      • 3.1 第一版
      • 3.2 第二版
      • 3.3 第三版
      • 3.4 第四版

1. 什么是单例模式?

提起单例模式,就必须介绍设计模式,而设计模式就是在软件设计中,针对特殊问题提出的解决方案。它是多年来针对一些常见的问题的解决方法,具有良好的可复用性、可扩展性和可维护性。
标准的设计模式有23种,单例模式就是最常见的一种,其目的是确认一个类只有一个实例对象,并且可以提供一个全局访问点来访问该实例。
单例就是指一个类的实例只有一个,即该类的所有对象都指向用同一个实例。
而多数单例模式并没有结合多线程,在多线程环境下运行有时会出现线程安全问题,所以下面不仅介绍如何实现单例模式,还有单例模式结合多线程使用时的相关知识。

2. 立即加载/“饿汉模式”

立即加载一般还被称作饿汉模式,根据立即,饿汉可以看出十分的急,所以在饿汉模式中,这样单例中的唯一实例对象就被创建。

创建MyObject.java代码如下:

//单例模式、饿汉模式
public class MyObject {//进行封装,防止创建新的对象private static MyObject object = new MyObject();private MyObject(){};//通过这个方法获得对象public static MyObject getObject(){return object;}
}

创建线程类MyThread.java:

public class MyThread extends Thread{@Overridepublic void run() {System.out.println(MyObject.getObject().hashCode());}
}

创建运行类Run.java:

public class Run {//测试单例模式对象是同一个public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.start();t2.start();t3.start();}
}

运行结果:
运行1
运行结果相同,说明对象是同一个,成功实现了立即加载型单例设计模式。

3. 延时加载/“懒汉模式”

延时,懒汉可以看出代码并不着急,所以懒汉模式型单例模式中的对象并不像饿汉模式中没有调用前就创建完成,而是在第一调用方法实例时才被创建。
对比饿汉模式:
优点:会减少内存资源浪费。
缺点:多线程环境并发运行,可能会出现线程安全。

3.1 第一版

创建类MyObjectLazy.java,代码如下:

public class MyObjectLazy {//单例模式、懒汉模式private static MyObjectLazy myObjectLazy = null;private static Object lock = new Object();private MyObjectLazy(){};public static MyObjectLazy getMyObjectLazy(){if(myObjectLazy != null){return myObjectLazy;}else{myObjectLazy = new MyObjectLazy();}return myObjectLazy;}}

创建线程类MyThreadLazy.java:

public class MyThreadLazy extends Thread{@Overridepublic void run() {System.out.println(MyObjectLazy.getMyObjectLazy().hashCode());}
}

创建运行类RunLazy.java:

public class RunLazy {//测试对象是不是同一个,是的话就是安全的单例模式public static void main(String[] args) {MyThreadLazy t1 = new MyThreadLazy();MyThreadLazy t2 = new MyThreadLazy();MyThreadLazy t3 = new MyThreadLazy();t1.start();t2.start();t3.start();}
}

运行结果:
1
结果不同,所以并不是单例模式,其中有问题,造成线程不安全。

3.2 第二版

第一版生成不同对象,所以造成非线程安全,我们可以做出一点修改,对代码加上锁。
修改后的MyObjectLazy.java:

    public static MyObjectLazy getMyObjectLazy(){synchronized (lock){if(myObjectLazy == null){myObjectLazy = new MyObjectLazy();}}return myObjectLazy;}

运行结果:
运行3
说明这个单例模式是正确实现了。

3.3 第三版

但是第二版又暴露一个问题,上面加锁后相当于整个方法都加锁,上面一个线程没有释放锁,下一个线程将无法运行,造成效率低下。
所以我们继续修改,修改后的MyObjectLazy.java:

    public static MyObjectLazy getMyObjectLazy(){try{if(myObjectLazy == null){Thread.sleep(1000);synchronized (lock){myObjectLazy = new MyObjectLazy();}}}catch(InterruptedException e){e.printStackTrace();}return myObjectLazy;}

运行结果:
3
运行结果又不同了,创建出了三个对象,为什么?这是因为虽然上了锁,但是if已经判断,只是new对象时串行。
虽然效率提高了,但这并不是单例模式。

3.4 第四版

我们可以使用DCL双检查锁机制来实现,进行两次if判断,使线程安全。
修改后MyObjectLazy.java:

    //再一次修改代码,加锁只加一块,并且应用DCL双检查机制来实现多线程环境下的延时加载单例模式,保证线程安全public static MyObjectLazy getMyObjectLazy(){try{if(myObjectLazy == null){Thread.sleep(1000);synchronized (lock){if(myObjectLazy == null) {myObjectLazy = new MyObjectLazy();}}}}catch(InterruptedException e){e.printStackTrace();}return myObjectLazy;}

运行结果:
4
使用双检查锁功能,成功解决了懒汉模式遇到多线程的问题。DCL经常出现在此场景下,我们要学会应用。

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

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

相关文章

Pycharm中出现ImportError:DLL load failed:找不到指定模块的解决方法

不论搭建什么工程,运行什么文件,只要在Pycharm中出现ImportError: DLL load failed: 找不到指定的模块这样的问题,以下方法都适用!!! 一、问题描述 我在使用pycharm连接webots,用python控制机…

element-ui el-table 树形结构 父子级联动

el-table 表格 为 select 和 select-all 设置回调函数 <el-table :data"tableData" id"yc_load" ref"yc_load" height"500px" border default-expand-allrow-key"showId" :tree-props"{children: children}"se…

OB Cloud助力泡泡玛特打造新一代分布式抽盒机系统

作为中国潮玩行业的领先者&#xff0c;泡泡玛特凭借 MOLLY、DIMOO、SKULLPANDA 等爆款 IP&#xff0c;以及线上线下全渠道营销收获了千万年轻人的喜爱&#xff0c;会员数达到 2600 多万。2022 年&#xff0c;泡泡玛特实现 46.2 亿元营收&#xff0c;其中线上渠道营收占比 41.8%…

Vue中过滤器如何使用?

过滤器是对即将显示的数据做进⼀步的筛选处理&#xff0c;然后进⾏显示&#xff0c;值得注意的是过滤器并没有改变原来 的数据&#xff0c;只是在原数据的基础上产⽣新的数据。过滤器分全局过滤器和本地过滤器&#xff08;局部过滤器&#xff09;。 目录 全局过滤器 本地过滤器…

判断EditText键盘输入的是中文还是英文,如何监听

为了判断EditText键盘输入的是中文还是英文&#xff0c;你可以使用InputMethodManager类来获取当前输入法的信息。在输入法切换时&#xff0c;你可以通过监听EditText的文本改变事件来判断输入法的类型。下面是一个简单的示例代码&#xff1a; // 监听EditText的文本改变事件 …

ROS实现一个节点同时发布订阅多个话题(C++版)

如果想在一个节点同时发布订阅多个话题就要使用到多线程机制&#xff0c;在C中如何使用多线程&#xff0c;在C中开多线程模板已经有了介绍&#xff0c;就是下面这个&#xff1a; #include<thread>void listenThread() {// 线程1内容 }void sendThread() {// 线程2内容 }…

前端面试基础面试题——6

1.CSS 隐藏元素的几种方法&#xff08;至少说出三种&#xff09; 2.页面导入样式时&#xff0c;使用 link 和import 有什么区别&#xff1f; 3.伪元素和伪类的区别&#xff1f; 4.行内元素和块级元素的具体区别是什么&#xff1f;行内元素的 padding 和 margin 可设置吗&…

将虚拟机网络适配器改为仅主机模式,Vmware弹出“仅主机模式适配器驱动程序似乎未运行

这个问题的原因是&#xff0c;主机上缺乏VMware安装后没有VMnet1和VMnet8网卡。 所以

win10下使用composer安装依赖ssl报错处理

报错&#xff1a;you are running Composer with SSL/TLS protection disabled. https://repo.packagist.org could not be fully loaded (curl error 60 while downloading https://repo.packagist.org/packages.json: SSL certificate problem: unable to get local issuer c…

Springboot 实践(13)spring boot 整合RabbitMq

前文讲解了RabbitMQ的下载和安装&#xff0c;此文讲解springboot整合RabbitMq实现消息的发送和消费。 1、创建web project项目&#xff0c;名称为“SpringbootAction-RabbitMQ” 2、修改pom.xml文件&#xff0c;添加amqp使用jar包 <!-- RabbitMQ --> <dependency&g…

EXCEL 中find,if and,if or

接上一篇sql中find函数的作用&#xff0c;由于工作需求是用帆软做报表&#xff0c;他的一些代码不仅有js&#xff0c;sql中的还有一些excel的相关知识&#xff0c;故作整理。 FIND() excel中的find原理和sql中相似&#xff0c;具体可查看 SQL函数 $FIND_Yangshiwei....的博客…

Python,如何安装lap,pip安装lap出现问题

Linux可以&#xff1a; pip install cpython pip install gitgit://github.com/gatagat/lap.gitwindows可以&#xff1a; 下载https://github.com/gatagat/lap 后解压&#xff0c; 安装pip install cpython 安装VS2019企业版&#xff1a; key BF8Y8-GN2QH-T84XB-QVY3B-RC4D…

自动化测试

1. 什么是自动化 1.1 自动化概念 自动化就是解放测试人员双手&#xff0c;测试工作由代码代替人工执行测试工作。 自动化不能完全代替手工测试。 自动化测试指软件测试的自动化&#xff0c;在预设状态下运行应用程序或系统&#xff0c;预设条件包括正常和异常&#xff0c;最…

qt 信号与槽机制,登录界面跳转

登录界面跳转 配置文件 .pro QT core gui texttospeechgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # d…

CSS3常用的新功能总结

CSS3常用的新功能包括圆角、阴渐变、2D变换、3D旋转、动画、viewpor和媒体查询。 圆角、阴影 border-redius 对一个元素实现圆角效果&#xff0c;是通过border-redius完成的。属性为两种方式&#xff1a; 一个属性值&#xff0c;表示设置所有四个角的半径为相同值&#xff…

免费SSL/TLS域名证书Certbot配置详细过程

文章目录 1. 在服务器上安装 Certbot2. 停止 web 服务器3. 运行 certbot 命令4. 证书生成位置5. 配置 web 服务器6. 重新加载 web 服务器7. 验证8. 配置自动续期发现问题1. Problem binding to port 80: Could not bind to IPv4 or IPv6.2. live directory exists for example.…

Clion 使用ffmpeg 学习1 开发环境配置

Clion 使用ffmpeg 学习1 开发环境配置 一、准备工作1. 准备环境2. 下载FFmpeg 二、操作步骤1. Clion 新建一个C项目2. 修改 CMakeLists.txt3. 修改配置4. 运行测试5. 打印rtsp 流信息的 demo 一、准备工作 在视频处理和多媒体应用程序开发中&#xff0c;FFmpeg 是一个强大的开…

MS1826A HDMI 多功能视频处理器 HDMI4进1出画面分割芯片

基本介绍 MS1826A 是一款多功能视频处理器&#xff0c;包含 4 路独立 HDMI 音视频输入通道、1 路 HDMI 音视 频输出通道以及 1 路独立可配置为输入或者输出的 SPDIF、I2S 音频信号。支持 4 个独立的字库定 制型 OSD&#xff1b;可处理隔行和逐行视频或者图形输入信号&#xff1…

数学建模--逻辑回归算法的Python实现

首先感谢CSDN上发布吴恩达的机器学习逻辑回归算法任务的各位大佬. 通过大佬的讲解和代码才勉强学会. 这篇文章也就是简单记录一下过程和代码. CSDN上写有关这类文章的大佬有很多,大家都可以多看一看学习学习. 机器学习方面主要还是过程和方法. 这篇文章只完成了线性可分方面的任…

Promise常用方法笔记

mixin.methods.getList(xxx) 是axios的二次封装 是通过Promise进行基本封装 let a mixin.methods.getList(toosSet.gettype);let b mixin.methods.getList(toosSet.gettypes);let c mixin.methods.getList(toosSet.gettypess);Promise.all([a, b, c]).then((res) > {aler…