5.单例模式问题3:多线程问题

单例模式多线程下不安全 单例模式多线程下不安全 大厂面试题: 1、请你谈谈对volatile的理解? 2、CAS你知道吗? 3、原子类AtomicInteger的ABA问题谈谈?原子更新引用知道吗? 4、我们都知道ArrayList是线程不安全的,请编码写一个不安全的案例并给出解决方案? 5、公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁。 6、CountDownLatch、Cyc... 阅读详情

一、单例模式的多线程问题

1. 什么是线程安全问题

当程序中存在多个线程,并且多个线程同时访问或修改同一份共享数据时,可能出现:

  • 数据状态不一致
  • 重复创建对象
  • 修改结果丢失
  • 集合读写异常
    这种问题通常称为多线程并发问题或线程安全问题。

二、单例对象为什么可能被创建多次

public static T Instance
{
    get
    {
        if (instance == null)
        {
            instance = CreateInstance();
        }

        return instance;
    }
}

假设线程 A 和线程 B 同时第一次访问,两个线程都可能通过:instance == null的判断,从而分别创建对象。这就破坏了单例的唯一性。

三、lock

C# 可以使用:lock。保证同一时刻只有一个线程进入指定代码块。
基本写法:

private static readonly object instanceLock = new object();

lock (instanceLock)
{
    // 需要保护的代码
}

执行过程:

线程 A 获得锁
    ↓
执行代码
    ↓
释放锁

线程 B 等待
    ↓
获得锁
    ↓
执行代码

lock 保护的是一段代码临界区,不是把整个对象“锁死”。

四、单例创建加锁

private static readonly object instanceLock = new object();

public static T Instance
{
    get
    {
        lock (instanceLock)
        {
            if (instance == null)
            {
                instance = CreateInstance();
            }

            return instance;
        }
    }
}

这样即使多个线程同时第一次访问 Instance,也只有一个线程能够创建对象。但是每次访问 Instance 都需要进入 lock。而单例通常只有第一次访问需要创建对象,之后只是返回已有实例。

五、双重检查锁

可以先在锁外判断一次:

public static T Instance
{
    get
    {
        if (instance == null)
        {
            lock (instanceLock)
            {
                if (instance == null)
                {
                    instance = CreateInstance();
                }
            }
        }
        return instance;
    }
}

这里出现了两次:

if (instance == null)

所以称为:Double-Checked Locking,双重检查锁

1. 第一次判断

if (instance == null)

作用:如果单例已经创建,直接返回。绝大多数访问不需要进入 lock。

2. 第二次判断

lock (instanceLock)
{
    if (instance == null)
    {
        instance = CreateInstance();
    }
}

六、非 MonoBehaviour 单例的线程安全写法

结合前面私有构造函数和反射,可以把创建逻辑单独封装:

using System;
using System.Reflection;

public class Singleton<T> where T : class
{
    private static T instance;
    private static readonly object instanceLock = new object();
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                lock (instanceLock)
                {
                    if (instance == null)
                    {
                        instance = CreateInstance();
                    }
                }
            }
            return instance;
        }
    }

    private static T CreateInstance()
    {
        ConstructorInfo constructor = typeof(T).GetConstructor(
            BindingFlags.Instance | BindingFlags.NonPublic,
            null,
            Type.EmptyTypes,
            null
        );

        if (constructor == null)
        {
            throw new InvalidOperationException(
                $"{typeof(T).Name} 必须拥有私有无参构造函数"
            );
        }
        return (T)constructor.Invoke(null);
    }
}

七、共享数据加锁

private readonly object dataLock = new object();
public void AddData(object data)
{
    lock (dataLock)
    {
        dataList.Add(data);
    }
}

八、所有共享访问都要遵守同一套加锁规则

不能只给:AddData()加锁,却让其他地方直接访问集合。
例如:

public void AddData(object data)
{
    lock (dataLock)
    {
        dataList.Add(data);
    }
}

如果另外一个方法:

public void RemoveData(object data)
{
    dataList.Remove(data);
}

没有使用同一个锁,仍然不安全。

public void RemoveData(object data)
{
    lock (dataLock)
    {
        dataList.Remove(data);
    }
}

只要操作的是同一份共享数据,就应该采用一致的同步策略。

九、MonoBehaviour 单例是否需要加锁

对于继承 MonoBehaviour 的单例,一般不要为了单例创建而加入多线程锁。
原因:Unity 中大量 API 都要求在主线程使用

GameObject
Transform
Instantiate()
Destroy()
AddComponent()

MonoBehaviour 本身也是由 Unity 主线程管理的。因此正常情况下都运行在 Unity 主线程。
如果整个 MonoBehaviour 单例只从主线程访问,就不存在多个线程同时执行 Awake() 创建单例的问题。

携程机票数据爬取实战:使用 Python 获取携程网机票信息 通过本篇博客,我们详细介绍了如何使用 Python 爬取携程网的机票信息,涉及了静态网页爬取(使用 Requests 和 BeautifulSoup)和动态网页爬取(使用 Selenium)两种方法。通过获取的数据,我们不仅能够进行票价分析,还可以构建更为复杂的预测模型或趋势分析工具。爬虫技术不仅能够帮助我们收集有价值的数据,还能够为商业决策提供数据支持。在实际应用中,我们可以结合更多的分析方法,如自然语言处理、图像处理等,进一步提升数据的价值。 阅读详情

相关推荐

STC15单片机实战项目软件开发第四讲 - 按键检测(状态机)

软件开发第四讲 - 按键检测(状态机) 一、工具链接 1、Keil c51 UV4 https://yunpan.360.cn/surl_yrIfYYmeRFk 2、STC-ISP下载软件 https://yunpan.360.cn/surl_yxH4CuUUvI3 二、学习板获取方式 方法1:自己设计PCB,自行打板焊接; 方法2:用群主设计的PCB,自行打板焊接; 方法3:向群主购买,淘宝链接...

硬件家园 3044

单例模式与多线程

在单例模式与多线程技术相结合的过程中,我们能发现许多以前从未考虑过的问题。这些不良的程序设计如果应用在商业项目中将会带来非常大的麻烦。线程与某些技术相结合时,我们需要考虑的事情会更多。总的来说,在本节我们只需要考虑一件事,那就是:如何使单例模式与多线程结合时是安全的、正确的。

m0_62943934的博客 1975

在没有实验数据的情况下,如何高效快速发表高影响因子论文

最新基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法

glldxh的博客 371

JAVA单例模式及多线程并发在单例模式中的影响

到的

qq_38254635的博客 1336

EDA课程实验:《数字逻辑电路》实验四___基于Minisys 平台 VIVADO工具与Verilog语言

(4)使用 Verilog HDL 实现一个分频器 clock_div,输入的是系统提供的 100MHz 频率,输出的是 1Hz 频率,占空比是 1:2,(实际上可以用一个加 1 计数器来实现降频,输入的是一个 100MHz 频率的方波,对这 个方波计数 1 亿次刚好到 1 秒(1Hz),题目要求输出频率占空比是 1:2,也就是这个 1Hz 的 方波高电平和低电平各 500ms,可以采用计数到中间值的时候输出电平翻转。(1)1) 拨动 SW1~0 为 01,按下 P4 按钮,GLD1~0 为 01;

ssjy_的博客 1295

随机子空间集成方法原理与scikit-learn实践

集成学习通过组合多个基学习器的预测结果来提升模型性能,是机器学习中的核心方法之一。随机子空间方法作为集成学习的重要变体,其核心原理是通过对特征空间进行随机子采样来增加模型多样性。这种方法特别适合处理高维数据,能有效缓解维度灾难问题,常与决策树、K近邻等对特征选择敏感的基学习器配合使用。在scikit-learn中,可以通过BaggingClassifier和BaggingRegressor实现随机子空间集成,关键参数包括max_features和n_estimators。实际应用中,该方法在金融风控、医疗诊

weixin_33773084的博客 376

Qt下实现支持多线程的单例模式

实现单例模式的代码很多。本文的单例模式实现代码是本人一直在工程项目中使用的,现拿出和大家交流分享。本文实现的单例模式,支持多线程,采用双重校验检索的方式,集成析构类,杜绝内存泄漏,稳定性好。使用C++/Qt的朋友们可以了解一下。不再废话,直接上代码。单例是一种软件设计模式,采用单例模式书写的类可以确保在一个工程中只有一个对象实例。再通俗点,就是一个类写好了之后,就不需要也无法再把这个类实例化了,因为写这个类的时候已经确保了有且仅有一个已经实例化的对象。这样不是很蠢么?

宁静致远的博客 1869

Unity 面试篇|(六)数据结构和算法篇 【全面总结 | 持续更新】

先拿10000个数建堆,然后一次添加剩余元素,如果大于堆顶的数(10000中最小的),将这个数替换堆顶,并调整结构使之仍然是一个最小堆,这样遍历完后,堆中的10000个数就是所需的最大的10000个。桶排序是计数排序的升级版。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。这样处理就可以分别在每个文件的10^6个数据中找出最大的10000个数,合并到一起在再找出1000*10000中的最终的结果。

游戏开发小Y的博客 12万+

多线程(5)——单例模式,阻塞队列

在之前,都是按照单线程来编写代码,这个代码执行下来,第一次判定和第二次判定的结论是一定相同的,但是现在是多线程模式了,实际开发中,单例类的构造方法可能是一个非常重量的方法,如果多次触发这个bug,就会浪费好几分钟的时间(加载时间翻倍)2.值加载文件的一小部分,就立即给用户显示,随着用户的翻页操作,在加载对应部分数据(懒汉模式)等待消费者处理,直接扔给阻塞队列,消费者不找⽣产者要数据,⽽是直接从阻塞队列⾥取.因为队列最大容量只有2,如果再入队列,就会触发阻塞了,take() 同理。

suger__salt的博客 1327

在PPT里如何做出晶莹剔透的高级水泡感出来呢

水晶汽泡被大量使用在TED场景的演讲片稿中,给人以强烈的视觉冲击感。其实实现很简单。本篇就用三步教会大家如何制作这样的一种PPT效果。

打造全国最全的AI Agent开发知识领域的博客 1534

Vue2 - 实现全景图Vr 720°全景效果查看预览功能,3D全景图流畅不卡顿渲染+手势拖拽+悬浮工具按钮,vue实现vr看720度全景效果方案讲解及示例代码(兼容电脑PC网页+手机H5移动端页面)

vue全景VR图,vue h5实现全景720预览,vue加载720全景图_vue怎么加载vr图片,vue实现vr全景看房,vue2实现全景效果,加载很慢卡怎么办,实现全景预览的插件,vue显示720度全景图,720°全景图显示,在h5中展示720°全景图,浏览全景图,基于vue实现vr全景预览,加载全景图,vue全景预览pannellum插件,vue实现3D全景图,实现720°全景图展示,在VUE 中使用three.js实现全景视频播放,vue项目中使用photo-sphere-viewer实现vr720度

🏆 前端领域优质创作者 3316

多线程中的单例模式

第一种写法:饿汉式 //饿汉式 public class SingleObject1 { private static final SingleObject1 instance = new SingleObject1(); private SingleObject1(){ } public static SingleObject1 getInstance(){ return instance; } } 第二种写法:懒汉式 1、迭代一: //懒

qq_38777614的博客 421

关务管理项目专题:SAP 与关衡关务系统的进出口报关业务集成(1)需求和方案整理

一个拥有进出口业务的企业就需要报关,而关务系统就是用来辅助企业日常进出口报关,同时数字化、合规化报关业务的有效工具。本章属于关务管理项目专题系列,以 SAP 与关衡关务系统的进出口报关业务集成为实例,详细讲解报关业务的需求和方案整理。

SAP李斌,本人承诺所有原创文章均不使用任何AI生成技术,请大家放心阅读。 2075

【大话设计模式】模式一 :单例模式与多线程

一、基本介绍 单例模式(Singleton),保证一个类仅仅有一个实例,并且提供一个访问它的全局访问点。 通常我们可以让一个全局变量使其被一个对象访问,但是它不能防止实例化多个对象。最好的方法就是,让类自身负责保存它的唯一实例,同时这个类保证没有其他实例可以被创建,并且它提供了一个访问该实例的方法。​​​ 模式构成要素: 私有构造方法 私有静态引用指向自己的实例 以自己实例为返回值的公有静态方法 二、模式应用场景及举例 1、适用场景:1.需要生成唯一序列的环境。 2.需要频繁实例化然后销毁

m0_46013789的博客 1587

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

JAVA多线程中的单例模式

在 Java 里,单例模式指的是一个类仅有一个实例,并且提供一个全局访问点(公有get方法)来获取该实例。在多线程环境下实现单例模式时,需要保证线程安全,避免多个线程同时创建多个实例。下面介绍几种常见的多线程单例模式实现方式。

weixin_65528013的博客 796

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

c# 多线程单例模式_创建型-单例模式

对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。 如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。 一个更好的解决办法是让类自身负责保存它的唯一实例...

weixin_32161697的博客 283

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

多线程下的单例模式

        单例模式就不在这里详细介绍了,这里要了解的是如何使单例模式遇到多线程是安全的。        单例模式分为饿汉模式和懒汉模式。        饿汉模式就类在加载的时候就创建实例,当使用类的时候已经将对象创建好了 public class SingletonMode1 { private static SingletonMode1 singletonMode1 = new ...

Morgan_Xiang的专栏 457

【多线程初阶】多线程案例之单例模式

本文主要给大家讲解多线程的一个重要案例 — 单例模式.单例模式是一种很经典的设计模式. 重点讲解单例模式中的饿汉模式和懒汉模式, 如何使其在多线程环境下也是安全的.

一些普普通通的学习笔记 1497

C++多线程5-单例模式详解

单例模式:只允许创建一个类对象,实现的关键是将构造函数变为私有。 单例模式有几种实现方式: 懒汉模式 饿汉模式 线程安全模式 局部静态变量模式 1.懒汉模式 当需要使用类对象时,才去申请堆空间,避免内存浪费,这样的方式会引入两个问题,一个就是在多线程的运用场景下有可能多次申请空间去创建对象造成异常,为了解决这个问题引入了线程安全模式;另外一个就是如何释放堆空间的问题,我们在线程安全模式下再讲解...

m0_37582216的博客 675

【JavaEE】【多线程】单例模式

单例模式是一种常用的设计模式,确保一个类只有一个实例,并提供一个全局访问点。在多线程环境下,我们需要特别注意如何保证线程安全,可以采用饿汉式单例、懒汉式单例、双重检查锁、静态内部类或枚举等方式。推荐使用静态内部类或枚举来实现单例模式,因为它们不仅能延迟实例化,还能确保线程安全,且代码简洁。单例模式不仅仅是保证类的唯一性,还能提升应用的性能和资源管理效率。希望本文的介绍能帮助你更好地理解单例模式的实现与应用。

小蜗牛的珍贵百宝箱 757

Spring单例模式多线程安全问题-有状态的Bean

Spring单例与线程安全小结 一、Spring单例模式与线程安全Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方。单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。 当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这是多个线程会并发执行该请求多

死磕到底的程序员 1838

单例模式Singleton 及其多线程

目录 一.单例模式的定义 单例模式的实现: 单例模式使用场景: 单例模式的优点: 单例模式的缺点: 注意事项: 单例模式类图: 单例模式Java模板: 二.单例模式与多线程 1.立即加载:“饿汉模式” 2.延迟加载:“懒汉模式” 3.静态内置类实现单例模式 4.序列化和反序列化的单例模式 5.使用static代码块实现单例模式 6.使用enum枚举数据实例实现单...

zuo_h_dr的博客 852

多线程安全的单例模式进阶

package com.MySingletonTest; /** * Created by liuxuanjie on 2020/01/08. * 单例模式的创建,保证多线程安全 * * ps: * 这是第一种方式,直接在类加载的时候创建一次 */ public class MySingleton1 { //私有静态自身引用 private static MySi...

romantic_jie的博客 390

C++11并发与多线程总结(四) --单例模式(Singleton)下的线程安全问题

(1)单例模式 1.单例 Singleton 是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一实例 2.一般用于操作数据池,或配置属性封装成类 3.外部不可创建,创建后指向指针也不可释放 (2)多线程获取单例模式接口 1.若多个线程同时接口,则可能在单例初始化时多个线程同时创建了多个单例,导致内存泄漏 2.解决以上问题必须对其部分...

Rice__的博客 915

单例模式在单线程和多线程中的不同写法

单例模式算是一种很常用到的设计模式之一了,今天就来聊一聊在不同场景下如何去实现单例。 单例模式的概念就是:保证一个类只有一个实例,并提供一个访问它的全局访问点。 主要作用呢,就是保证在Java应用程序中,一个类Class只有一个实例存在。 单例模式一般分为 懒汉式 以及 饿汉式。 单例的几种写法: 1.懒汉式(立即加载方式) public class Singleton { privat...

yuki_qaq的博客 830

python 单例 多线程_python 单例模式

# 记录两种常用的单例模式# 第一种import threadingimport timeclass Singleton(object):_instance = Nonedef __init__(self):time.sleep(3)@classmethoddef instance(cls, *args, **kwargs):if not cls._instance:cls._instance...

weixin_39675038的博客 380
上一篇: 4.单例模式问题2:重复挂载
下一篇: 6.单例模式:懒汉式单例
Unity黑马王子
博客等级 码龄4年 1846粉丝 181原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值