首页 > 其他分享 >多线程下单例模式延迟初始化的实现

多线程下单例模式延迟初始化的实现

时间:2024-09-27 21:49:29浏览次数:10  
标签:初始化 下单 对象 步骤 volatile 单例 线程 多线程

多线程下单例模式延迟初始化的实现


前言

在程序开发中,存在一些开销较高的资源,例如数据库连接等,我们使用单例模式保证其唯一并且进行延迟初始化,只有当使用的时候才进行初始化,避免资源的浪。单线程的单例模式的实现较为简单,我们来讲讲在多线程下单例模式的实现

synchronized修饰方法

单例模式延迟初始化的实现最简单的方式莫过于直接使用synchronized修饰方法,但是如果有大量线程同时调用该方法,就会导致大量线程的阻塞在方法外边,只能一个一个的获取实例,严重影响系统性能,我们只需要保证对象的初始化由单个线程执行即可

在这里插入图片描述

双重检查锁定

第一次判断非空:防止线程阻塞,在单例对象进行初始化后直接返回,大大提高了程序性能
第二次判断非空:可能由多个线程阻塞在同步块外,进行非空检验可以避免单例对象的重复创建
在这里插入图片描述

双重检查锁定的问题

在上方双重检查锁定的实现中,其实存在问题,问题出现在instance=new Instance(),这一行可以分为三步:
1、分配对象的内存空间
2、初始化对象
3、将instance指向刚分配的内存空间
对于单线程来说,当重排序改变执行的结果时,禁止重排序,而步骤二和步骤三交换并不会改变单线程的执行结果,因此为了优化程序的性能,编译器和处理器可能会对步骤二和步骤三重排序。这就可能导致线程进行步骤一和三之后,另一个形成判断非空,将访问到一个还没有被初始化的对象。
在这里插入图片描述
要解决这个问题有两个办法:
1:禁止步骤二和步骤三重排序。
2:允许步骤二和步骤三重排序,不能别的线程"看到"即可

基于volatile的双重锁定方案

对于方法一:我们自然而然的想到了volatile变量,使用volatile修饰单例,volatile写通过加入屏障防止步骤二和步骤三进行重排序。

在这里插入图片描述

类初始化

对于方法二:我们采用静态变量的初始化来解决,JVM在类初始化阶段会执行静态变量的初始化,静态变量的初始化只有一次。当线程进行类的初始化时,JVM会获取一个锁。若有多个线程同时需要进行类的初始化,那么每个线程至少都要获取一次锁来确保类是否被初始化,线程初始化一个state变量,用来标记类是否初始化,当线程获取锁时,通过state变量判断是否需要进行初始化。

在这里插入图片描述

总结

本文介绍了基于volatile的双重锁定方案和基于类初始化的方案实现多线程下单例模式延迟初始化的实现,通过对比,我们发现类初始化代码更加简洁,但类初始化只适用于静态对象的单例实现,而基于volatile的双重锁定方案使用于静态对象和实例对象的单例实现。
字段延迟初始化降低了单例模式创建对象的开销,但是增加了多线程并发访问对象初始化的开销。大部分情况下正常初始化优于延迟初始化,当需要进行延迟初始化时,若单例对象为静态对象,使用volatile的双重锁定方案实现,若单例对象为实例对象,使用类初始化的方案

标签:初始化,下单,对象,步骤,volatile,单例,线程,多线程
From: https://blog.csdn.net/m0_71338251/article/details/142601847

相关文章

  • 构造函数初始化列表 的好处
    初始化类成员的两种方式:(1)使用初始化列表;(2)在构造函数体内进行赋值操作。classPoint{public:Point(intxx,intyy):x(xx),y(yy){cout<<"ConstructorofPoint"<<endl;}private:floatx,y;};class......
  • 初始化的代码块和@PostConstruct有什么区别
    背景    在实际开发中,我们经常会需要进行一些初始化操作,比如进行一些预加载和赋值之类的。在代码中,常见的有通过静态代码块、非静态代码块,@PostConstruct来实现初始化。那么既然他们都可以实现初始化操作,那么他们有什么区别呢?使用方式静态代码块:是用 static 关键......
  • javaseday31多线程
    什么是多线程线程与进程小结并发和并行并发并行小结 多线程的实现方式方法一publicclassDemo1{publicstaticvoidmain(String[]args){//使用多线程的第一种方法/***1、创建一个类继承Thread类*2、并重写......
  • 信息学奥赛复赛复习04-CSP-J2019-04-加工零件-位运算、整数映射0或1、结构体、初始化
    PDF文档回复:20240926<12019CSP-J题目4加工零件[题目描述]凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇。工厂里有n位工人,工人们从1∼n编号。某些工人之间存在双向的零件传送带。保证每两名工人之间最多只存在一条传送带如果......
  • 信息学奥赛复赛复习04-CSP-J2019-04-加工零件-位运算、整数映射0或1、结构体、初始化
    PDF文档公众号回复关键字:2024092612019CSP-J题目4加工零件[题目描述]凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇。工厂里有n位工人,工人们从1∼n编号。某些工人之间存在双向的零件传送带。保证每两名工人之间最多只存在一条传送带......
  • 初始化列表
    作用:C++提供了初始化列表语法,用来初始化属性语法:构造函数():属性1(值1),属性2(值2)...{}#include<iostream>usingnamespacestd;classPerson{public: //传统初始化操作 /*Person(inta,intb,intc) { _A=a; _B=b; _C=c; }*///初始化列表初始......
  • .NetCore MySqlException 多线程中(There is already an open DataReader associated w
    问题描述:其实标题只是遇到问题的其中之一,遇到三种异常信息如下:Lockwaittimeoutexceeded;tryrestartingtransaction大概意思:超过锁定等待超时;尝试重新启动事务 ThereisalreadyanopenDataReaderassociatedwiththisConnectionwhichmustbeclosedfirst.大......
  • 多线程极速导出/9字段10W行只需2秒/导入导出打印组件/功能丰富简单易用
    一、功能特点组件同时集成了导出数据到csv、xls、pdf和打印数据。所有操作全部提供静态方法无需new,数据和属性等各种参数设置采用结构体数据,极为方便。同时支持QTableView、QTableWidget、QStandardItemModel、QSqlTableModel等数据源。提供静态方法直接传入QTableView、QTab......
  • Redis6 多线程模型
    优质博文:IT-BLOG-CN一、单线程的优缺点对于一个请求操作Redis主要做3件事情:从客户端读取数据/解析、执行Redis命令、回写数据给客户端。所以主线程其实就是把所有操作的这3件事情串行一起执行,因为是基于内存,所以执行速度非常快。优点&缺点:【1】优点:不存在锁的竞争问题和......
  • 银行存取款多线程
    importjava.util.Random;importjava.lang.*;/***银行存取款**@authorLaccoliths*/publicclassBank{privateintcount=0;/***存钱*@parammoney:存钱数*/publicsynchronizedvoidaddMoney(intmoney){count+......