iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >DCL和Singleton模式的问题怎么解决
  • 766
分享到

DCL和Singleton模式的问题怎么解决

2023-06-18 00:06:37 766人浏览 独家记忆
摘要

本篇内容主要讲解“DCL和Singleton模式的问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“DCL和Singleton模式的问题怎么解决”吧!在多线程的情况下Singleton模

本篇内容主要讲解“DCL和Singleton模式的问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“DCL和Singleton模式的问题怎么解决”吧!

多线程的情况下Singleton模式会遇到不少问题,一个简单的例子

1:  class Singleton {      2:      private static Singleton instance = null;      3:         4:      public static Singleton instance() {      5:          if (instance == null) {      6:              instance = new Singleton();      7:          }      8:          return instance;     9:      }     10:  }

假设这样一个场景,有两个线程调用Singleton.instance(),首先线程一判断instance是否等于null,判断完后一瞬间虚拟机把线程二调度为运行线程,线程二再次判断instance是否为null,然后创建一个Singleton实例,线程二的时间片用完后,线程一被唤醒,接下来它执行的代码依然是instance = new Singleton();
两次调用返回了不同的对象,出现问题了。

最简单的方法自然是在类被载入时就初始化这个对象:private static Singleton instance = new Singleton();

JLS(Java Language Specification)中规定了一个类只会被初始化一次,所以这样做肯定是没问题的。

但是如果要实现延迟初始化(Lazy initialization),比如这个实例初始化时的参数要在运行期才能确定,应该怎么做呢?

依然有最简单的方法:使用synchronized关键字修饰初始化方法:

public synchronized static Singleton instance() {              if (instance == null) {          instance = new Singleton();      }      return instance;  }

这里有一个性能问题:多个线程同时访问这个方法时,会因为同步而导致每次只有一个线程运行,影响程序性能。而事实上初始化完毕后只需要简单的返回instance的引用就行了。

双检测锁定解决方案

DCL是一个“看似”有效的解决方法,先把对应代码放上来吧:

    1 :   class Singleton {       2 :       private static Singleton instance = null ;       3 :          4 :       public static Singleton instance() {       5 :           if (instance == null ) {    6 :               synchronized (this) {       7 :                   if (instance == null)    8 :                      instance = new Singleton();    9 :              }    10 :          }    11 :          return instance;    12 :      }    13 :  }

用JavaWorld上对应文章的标题来评论这种做法就是smart, but broken。来看原因:

Java编译器为了提高程序性能会进行指令调度,CPU在执行指令时同样出于性能会乱序执行(至少现在用的大多数通用处理器都是out-of-order的),另外cache的存在也会改变数据回写内存时的顺序[2]。JMM(Java Memory Model, 见[1])指出所有的这些优化都是允许的,只要运行结果和严格按顺序执行所得的结果一样即可。

Java假设每个线程都跑在自己的处理器上,享有自己的内存,和共享的主存交互。注意即使在单核上这种模型也是有意义的,考虑到cache和寄存器会保存部分临时变量。理论上每个线程修改自己的内存后,必须立即更新对应的主存内容。但是Java设计师们认为这种约束会影响程序性能,他们试着创造了一套让程序跑得更快、但又保证线程之间的交互与预期一致的内存模型。

synchronized关键字便是其中一把利器。事实上,synchronized块的实现和linux中的信号量(semaphore)还是有区别的,前者过程中的获得和释放都会都会引发一次Memory Barrier来强制线程本地内存和主存之间的同步。通过这个机制,Java中的同步机制保证了synchronized块中指令的原子性(atomic)。

双检测锁定的问题

好了,回过头来看DCL问题。看起来访问一个未同步的instance字段不会产生什么问题,我们再次来假设一个场景:

线程一进入同步块,执行instance = new Singleton(); 线程二刚开始执行getResource();

按照顺序的话,接下来应该执行的步骤是 1) 分配新的Singleton对象的内存 2) 调用Singleton的构造器,初始化成员字段 3) instance被赋为指向新的对象的引用。

前面说过,编译器或处理器都为了提高性能都有可能进行指令的乱序执行,线程一的真正执行步骤可能是1) 分配内存 2) instance指向新对象 3) 初始化新实例。如果线程二在2完成后3执行前被唤醒,它看到了一个不为null的instance,跳出方法体走了,带着一个还没初始化的Singleton对象。

错误发生的一种情形就是这样,关于更详细的编译器指令调度导致的问题,可以参看这个网页 [4]。

[3] 中提供了一个编译器指令调度的证据

instance = new Singleton(); 这条命令在Symantec JIT中被编译成

0206106A   mov         eax,0F97E78h  0206106F   call        01F6B210                  ; 分配空间  02061074   mov         dWord ptr [ebp],eax       ; EBP中保存了instance的地址    02061077   mov         ecx,dword ptr [eax]       ; 解引用,获得新的指针地址    02061079   mov         dword ptr [ecx],100h      ; 接下来四行是inline后的构造器  0206107F   mov         dword ptr [ecx+4],200h      02061086   mov         dword ptr [ecx+8],400h  0206108D   mov         dword ptr [ecx+0Ch],0F84030h

可以看到,赋值完成在初始化之前,而这是JLS允许的。

另一种情形是,假设线程一安稳地完成Singleton对象的初始化,退出了同步块,并同步了和本地内存和主存。线程二来了,看到一个非空的引用,拿走。注意线程二没有执行一个Read Barrier,因为它根本就没进后面的同步块。所以很有可能此时它看到的数据是陈旧的。

还有很多人根据已知的几种提出了一个又一个fix的方法,但最终还是出现了更多的问题。可以参阅[3]中的介绍。

[5]中还说明了即使把instance字段声明为volatile还是无法避免错误的原因。

由此可见,安全的Singleton的构造一般只有两种方法,一是在类载入时就创建该实例,二是使用性能较差的synchronized方法。

到此,相信大家对“DCL和Singleton模式的问题怎么解决”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: DCL和Singleton模式的问题怎么解决

本文链接: https://www.lsjlt.com/news/294828.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • DCL和Singleton模式的问题怎么解决
    本篇内容主要讲解“DCL和Singleton模式的问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“DCL和Singleton模式的问题怎么解决”吧!在多线程的情况下Singleton模...
    99+
    2023-06-18
  • java单例模式和线程安全问题怎么解决
    这篇文章主要介绍“java单例模式和线程安全问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“java单例模式和线程安全问题怎么解决”文章能帮助大家解决问题。单例模式、多实例模式、和线程安全...
    99+
    2023-07-05
  • sql模式设置引起的问题怎么解决
    今天小编给大家分享一下sql模式设置引起的问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1 报错类似如下数据库错...
    99+
    2023-06-30
  • Java单例模式中的线程安全问题怎么解决
    今天小编给大家分享一下Java单例模式中的线程安全问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一. 使用多线程...
    99+
    2023-07-02
  • PHP设计模式:用于解决特定软件问题的模式
    php 设计模式提供了已知解决方案来应对软件开发中常见的问题。常见的模式类型包括创建型(例如工厂方法模式)、结构型(例如装饰器模式)和行为型(例如观察者模式)。设计模式在解决重复性问题、...
    99+
    2024-05-13
    php 设计模式
  • 怎么解决电脑只能进入安全模式问题
    这篇文章主要介绍“怎么解决电脑只能进入安全模式问题”,在日常操作中,相信很多人在怎么解决电脑只能进入安全模式问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么解决电脑只能进入安全模式问题”的疑惑有所帮助!...
    99+
    2023-06-28
  • 怎么解决SQLServer附加数据库是只读模式的问题
    本篇内容主要讲解“怎么解决SQLServer附加数据库是只读模式的问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么解决SQLServer附加数据库是只读模...
    99+
    2024-04-02
  • 怎么解决分布式session问题
    本篇内容介绍了“怎么解决分布式session问题”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!sessio...
    99+
    2024-04-02
  • C++访问者模式模板函数无法重载的问题解决
    目录背景 解决方案 最终代码 背景 最近遇到一个比较棘手的场景,我们有一堆模块,他们有一个通用的基类,我们不防假设为 BaseClass,该类有一些通用的结构以及需要重载的方法。这...
    99+
    2024-04-02
  • java单例模式解决了哪些问题
    Java单例模式解决了以下问题: 限制了类的实例化,保证一个类只有一个实例。这样可以节省系统资源,提高性能。 提供了对类实例...
    99+
    2023-10-20
    java
  • sql模式设置引起的问题解决办法
    目录1 报错类似如下2 解决办法2.1 查看全局sql模式2.2 设置全局sql模式2.3 查看当前sql模式2.4 设置当前sql模式3 永久生效的解决办法3.1 找到my.cnf...
    99+
    2024-04-02
  • win10系统怎么解决飞行模式无法关闭问题
    这篇文章将为大家详细讲解有关win10系统怎么解决飞行模式无法关闭问题,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在Cortana搜索栏输入msconfig后,按回车键启动“系统配置”。点击“服务”选项...
    99+
    2023-06-28
  • 解决Windows7网络模式锁死问题的方法
    随着Windows7系统的发布,越来越多的用户开始使用windows7系统,虽说windows系统的功能大同小异,但是仍有用户在使用windows7的过程中出现这样或那样的问题,下面就是教大家解决Windows7网络模...
    99+
    2023-05-25
    网络模式锁死 模式 网络 问题 Windows7 方法
  • SAP Hybris和Netweaver的集群模式以及集群模式下工作需要解决的问题是什么
    本篇文章给大家分享的是有关SAP Hybris和Netweaver的集群模式以及集群模式下工作需要解决的问题是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Hybris支持...
    99+
    2023-06-04
  • S模式下的Windows10和Windows11常见问题解答
    在S模式下的Windows10和Windows11常见问题解答:1. 什么是S模式?S模式是一种安全模式,限制用户只能安装和运行来自...
    99+
    2023-09-14
    Windows10
  • BootStrap怎么解决模态框闪退问题
    小编给大家分享一下BootStrap怎么解决模态框闪退问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!代码如下<!--搜...
    99+
    2024-04-02
  • python selenium模拟点击问题怎么解决
    这篇文章主要介绍“python selenium模拟点击问题怎么解决”,在日常操作中,相信很多人在python selenium模拟点击问题怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家...
    99+
    2023-06-30
  • Android模版制作的常见问题怎么解决
    今天小编给大家分享一下Android模版制作的常见问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。为什么在后台添加...
    99+
    2023-06-26
  • SpringMVC中的跳转方式和视图解析器问题怎么解决
    这篇文章主要介绍“SpringMVC中的跳转方式和视图解析器问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringMVC中的跳转方式和视图解析器问题怎么解决”文章能帮助大家解决问题。...
    99+
    2023-07-04
  • html格式显示note的问题怎么解决
    本篇内容介绍了“html格式显示note的问题怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!如果webclient ui里某个Opp...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作