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

文章目录

    • 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.rhkb.cn/news/116136.html

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

相关文章

Vue2项目练手——通用后台管理项目第一节

Vue2项目练手——通用后台管理项目 知识补充yarn和npm区别npm的缺点:yarn的优点 npm查看镜像和设置镜像 项目介绍项目的技术栈 项目搭建文件目录 创建路由,引入element-uirouter/index.jsmain.jspages/Users.vuepages/Main.vuepages/Home.vuepages/Login…

linux C++ 海康截图Demo

项目结构 CMakeLists.txt cmake_minimum_required(VERSION 3.7)project(CapPictureTest)include_directories(include)link_directories(${CMAKE_SOURCE_DIR}/lib ${CMAKE_SOURCE_DIR}/lib/HCNetSDKCom) add_executable(CapPictureTest ${CMAKE_SOURCE_DIR}/src/CapPictureTes…

ChatGPT 一条命令总结Mysql所有知识点

想学习Mysql的同学,可以使用ChatGPT直接总结mysql所有的内容与知识点大纲 输入 总结Mysql数据库所有内容大纲与大纲细分内容 ChatGPT不光生成内容,并且直接完成了思维导图。 AIGC ChatGPT ,BI商业智能, 可视化Tableau, PowerBI, FineReport, 数据库Mysql Oracle, Offi…

Leetcode Top 100 Liked Questions(序号141~189)

​ 141. Linked List Cycle ​ 题意:给你一个链表,判断链表有没有环 我的思路 两个指针,一个每次走两步,一个每次走一步,如果走两步的那个走到了NULL,那说明没有环,如果两个指针指向相等&…

使用Windbg动态调试排查软件启动不了的问题

目录 1、问题说明 2、初步分析 3、使用Windbg启动程序进行动态调试 4、进一步分析 5、何时使用Windbg静态分析?何时使用Windbg进行动态调试? 6、最后 VC常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...&…

Linux中创建文件夹,删除文件夹

Linux中创建目录:mkdir 文件夹, 比如:mkdir test 删除文件夹:rm -rf 文件夹, 比如:rm -rf soft vi强制不保存退出命令:q!

YOLOv5算法改进(12)— 替换主干网络之Swin Transformer

前言:Hello大家好,我是小哥谈。Swin Transformer是一种基于Transformer的深度学习模型,它在视觉任务中表现出色。与之前的Vision Transformer(ViT)不同,Swin Transformer具有高效和精确的特性,并…

合宙Air724UG LuatOS-Air LVGL API控件--复选框 (Checkbox)

复选框 (Checkbox) 复选框主要是让用户进行一些内容选择,或者同意用户协议。 示例代码 – 复选框回调函数 function event_handler(obj, event) if event lvgl.EVENT_VALUE_CHANGED then print(“State”, lvgl.checkbox_is_checked(obj)) end end – 创建复选框…

图像处理简介

目录 基本术语 1 .图像(image) 1.1 像素(Pixel) 1.2 颜色深度(Color Depth) 1.3 分辨率(Resolution) 1.4 像素宽高比(Pixel Aspect Ratio) 1.5 帧率(FPS) 1.6 码率(BR) 1. …

sql各种注入案例

目录 1.报错注入七大常用函数 1)ST_LatFromGeoHash (mysql>5.7.x) 2)ST_LongFromGeoHash &#xff08;mysql>5.7.x&#xff09; 3)GTID (MySQL > 5.6.X - 显错<200) 3.1 GTID 3.2 函数详解 3.3 注入过程( payload ) 4)ST_Pointfromgeohash (mysql>5.…

day28 异常

to{}catch{} try{}catch{}的流传输 try {fis new FileInputStream("file-APP\\fos.txt");fos new FileOutputStream("fos.txt");int a ;while ((a fis.read())! -1){fos.write(a);}System.out.println(a); } catch (IOException e) {e.printStackTrace()…

关于Maxwell与Kafka和数据库的监控

1.Maxwell的配置 其实就是配置两端的配置信息,都要能连接上,然后才能去传输数据 config.properties #Maxwell数据发送目的地&#xff0c;可选配置有stdout|file|kafka|kinesis|pubsub|sqs|rabbitmq|redis producerkafka # 目标Kafka集群地址 kafka.bootstrap.servershadoop102…

机器学习概念

目录 一、人工智能、机器学习、深度学习的关系 二、什么是深度学习&#xff1f; 2.1 深度学习常用算法 一、人工智能、机器学习、深度学习的关系 人工智能、机器学习和深度学习的关系如下所示。 二、什么是深度学习&#xff1f; 深度学习( DL, Deep Learning) 是机器学习 …

【操作记录】pytorch_geometric安装方法

pytorch_geometric安装方法 github地址 主要不要直接pip install安装&#xff0c;会由于依赖无法安装而失败 点击here手动安装依赖 选择对应的pytorch版本&#xff0c;我的是Win10 Python3.8.3Pytorch1.8.1CUDA10.2 手动下载四个依赖包本地安装&#xff1a; 主要不要直接&am…

【深度学习】ChatGPT

本文基于Andrej Karpathy(OpenAI 联合创始人&#xff0c;曾担任特斯拉的人工智能和自动驾驶视觉主管)在Microsoft Build 2023上的演讲整理而成&#xff08;完整的视频在文末&#xff0c;直接拖到文章底部&#xff09;&#xff0c;主要分为2大部分&#xff1a; 1.如何训练GPT(可…

Git和Github的基本用法

目录 背景 下载安装 安装 git for windows 安装 tortoise git 使用 Github 创建项目 注册账号 创建项目 下载项目到本地 Git 操作的三板斧 放入代码 三板斧第一招: git add 三板斧第二招: git commit 三板斧第三招: git push 小结 &#x1f388;个人主页&#xf…

一文了解tcp/ip协议的运行原理

接触代理ip的人都了解https/sock5等ip协议&#xff0c;那么TCP/IP 协议又是什么&#xff1f; 一、什么是TCP/IP 协议&#xff1f; TCP/IP 协议实际上是一系列网络通信协议的一个统称&#xff0c;他负责具体的数据传输工作&#xff0c;核心的两个协议包括TCP以及IP&#xff0c…

搭建STM32F407的Freertos系统(基于STM32CubeMX)

本人长期开发Linux、Windows上应用软件&#xff0c;一直以来MCU开发有所接触&#xff0c;但较少&#xff08;最近项目需要&#xff0c;小公司么&#xff0c;都得会&#xff0c;被逼的&#xff09;&#xff0c;好在有STM32CubeMX这样工具&#xff0c;貌似就是我想要的工具。 本次…

自然语言处理实战项目16- 基于CPU的大语言模型的实战训练全流程指导,模型调优与评估

大家好,我是微学AI,今天给大家介绍一下自然语言处理实战项目16- 基于CPU的生成式大语言模型的实战训练全流程详细讲解,模型调优与评估。该流程涵盖了数据准备、数据预处理、词表构建、模型选择与配置、模型训练、模型调优和模型评估等步骤。通过不断迭代和优化,可以提高模型…

C++信息学奥赛1184:明明的随机数

#include <bits/stdc.h> using namespace std; int main() {int n; // 数组长度cin >> n; // 输入数组长度int arr[n]; // 定义整数数组&#xff0c;用于存储输入的整数// 输入数组元素for (int i 0; i < n; i){cin >> arr[i];}int e 0; // 计数器&…