Java中的双重检查锁定

在本文中,我们将介绍在RxJava中创建Singleton对象的一些技术。 最重要的是,我们将学习Java中的双重检查锁定

Java中的Singleton模式是一种创新模式。 随着时间的流逝,人们开始关注Singleton模式的使用和实现。 这是由于单例的实现和使用方式存在一些非常根本的问题所致。

Java中的单例模式具有多种功能,例如:

  1. 确保只有一个类实例存在于JVM中。
  2. 提供对类实例的全局访问。
  3. 防止直接创建类实例的私有构造函数。
  4. 最适合用于日志记录,线程池,缓存等…

使用Java创建Singleton模式的三种基本方法。 我将列出所有这些内容,并告诉您单例模式是如何随着时间演变的,以及为什么双重检查锁定是当前最好的方法。

这是Java中Singleton模式的基本实现。

 class Example{     private Example mExample = null ;   public Example getInstance (){ if (mExample == null ) mExample = new Example (); return mExample; } // rest of the code...  } 

注意:构造函数在所有实现中都是私有的。

此代码将在多线程上下文中失败。 多个线程可以调用getInstance()方法并最终创建Singleton的多个实例。 这是不希望的行为。 Singleton的基本属性是,JVM中应该只有该类的单个实例。

优点:

  • 易于阅读。
  • 在单线程应用程序中可以正常工作。

缺点:

  • 在多线程上下文中将失败。
  • 多个线程可以创建此类的多个实例。
  • 将无法达到Singletons的目的。

一些聪明的人想到了创建单例的优雅解决方案。 我们使用synced关键字来防止线程同时访问getInstance()方法。

 class Example{     private Example mExample = null ;   public synchronized Example getInstance (){ if (mExample == null ) mExample = new Example (); return mExample; } // rest of the code...  } 

通过使用synced关键字,我们是JVM,一次只能让一个字段访问此方法。 这解决了多线程上下文的问题。

如果您看一下上面的代码,您会注意到我们已经使整个方法同步。 每个访问该方法的线程都将首先获取一个锁。

同步或获取锁是一种昂贵的方法。 确实会降低应用程序的性能。 如果您想进一步了解同步的性能开销,那么这个SO答案将是一个好的开始。

即使所有线程都获得了锁定,它也只是需要锁定的第一个线程。 初始化对象后,空检查足以在线程之间维护单个实例。

优点:

  • 确实很好地处理了多线程环境。
  • 容易明白。

缺点:

  • 每当线程尝试访问该方法时,获取不必要的锁定。
  • 锁定确实非常昂贵,并且许多线程都想获得一个锁定,这会导致严重的性能开销。

在先前的方法中,我们将整个方法同步为线程安全的。 但是同步不仅适用于方法。 我们也可以创建同步块。

在此方法中,我们将创建一个同步块而不是整个方法。

 class Example{     private Example mExample = null ;   public Example getInstance (){ if (mExample == null ){ synchronized (Example. class ){ if (mExample == null ) mExample = new Example (); } } return mExample; } // rest of the code...  } 

这是步骤顺序:

  • 第一个线程调用getInstance()方法。
  • 它检查实例是否为空(对于第一个线程,它为)。
  • 然后,它获取一个锁。
  • 检查该字段是否仍然为空?
  • 如果是,它将创建该类的新实例并初始化该字段。 最后,返回实例。
  • 其余线程不需要获取锁定,因为字段已经初始化,因此降低了同步命中率!

注意同步块之前和之后的多个空检查。 因此,名称为double check lock

优点:

  • 在多线程环境中工作。
  • 比同步方法具有更好的性能。
  • 只有第一个线程需要获取锁。
  • 以上方法中最好的。

缺点:

  • 一开始,双重null检查可能会造成混淆。
  • 不行!!

是的,上述方法存在一个细微问题。 它并不总是有效。

问题在于,编译器对程序的感觉与人眼的感觉截然不同。 根据我们的逻辑,首先,应创建Example类的实例,然后将其分配给mExample字段。

但是不能保证此操作顺序。 编译器可以自由地对语句进行重新排序,只要它不影响最终结果即可。

因此,例如,您可能最终会将部分初始化的对象分配给mExample字段。 然后其他线程将对象视为非空。 这导致线程使用部分初始化的对象,这可能导致崩溃

如今,编译器对您的代码进行了某些优化,使他们可以自由地对语句进行重新排序。 当编译器内联构造函数调用时,可能会发生重新排序。

Doug Lea写了一篇有关基于编译器的重新排序的详细文章。

Paul Jakubik发现了使用双重检查锁定无法正常工作的示例。

如果上述所有方法都容易失败,那么我们还剩下什么?

在J2SE 5.0中,Java的内存模型发生了很大变化。 volatile关键字现在可以解决上述问题。

Java平台不允许将易失字段的读取或写入与之前的任何读取或写入重新排序。

 class Example{     private volatile Example mExample = null ;   public Example getInstance (){ if (mExample == null ){ synchronized (Example. class ){ if (mExample == null ) mExample = new Example (); } } return mExample; } // rest of the code...  } 

当心:仅在JDK 5及更高版本中有效。 对于android开发人员,您最好选择使用Java 7及更高版本的Java。

希望您觉得本文有用。 如果您愿意,请在下面的评论部分中告诉我,我很乐意写更多这样的概念文章。

翻译自: https://www.javacodegeeks.com/2019/09/double-check-locking-java.html

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

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

相关文章

视频干扰的原因及解决方法

我们在视频监控和视频传输会议中常常会遇到视频信号被干扰的困扰,由于视频干扰产生画面抖动、显示模糊等显示问题,严重影响使用效果。那么这些干扰信号时如何产生的,又该如何解决呢?接下来我们就跟随飞畅科技的小编一起来详细了解…

网络监控系统安装的4种方式,安防必备

现如今,随着人们安防意识的提高,监控从业人员也越来越多。对于刚刚加入这个行业的新人来讲,可能首先要从最基层的监控设备安装做起。只有在实践中不断积累经验技术,才有可能独当一面、快速成长。作为一名新手,网络监控…

it编年史_Java的编年史和低延迟

it编年史总览 我正在看Typesafe的Rolan Kuhn在介绍React流方面的精彩演讲,乍一看似乎与《纪事报》有一些相似的目标,但是当您深入研究细节时,很明显我有一些关键的假设根本不同。 关键假设 《纪事》设计的主要假设是 低延迟是您的问题&#…

智慧磐石工程项目系统组成

武警部队智慧磐石工程以五防一体化建设为基础,融入各类前沿智能检测、识别、控制等相关技术,通过整合指挥、监控、防护、报警、通信、处置要素,实现信息智能管理、环境智能分析、通道智能防范、监控智能识别、险情智能感知、枪弹智能管控、情…

网络延长器分为哪几类?其应用领域有哪些?

网络延长器具有超低传输时延,能够线速转发数据包。网络延长器采用自主产权的LRE(Long- Reacher Ethernet)长线以太网驱动技术,能有效延长以太网传输距离达700米,同时保障最大传输带宽。基本原理是通过信号整形放大&…

Java项目:书评

本文是关于这本书的 Peter Verhas撰写的Java Projects Second Edition 我去年写的 这样一篇文章的目的通常是为了促进这本书的销售。 在这种情况下没有什么不同,但是由于这是我写的书,而且我是撰写评论的人,因此赞美这本书将非常尴尬。 所以…

信号延长器常见故障问题及解决方案汇总

延长器是用来延长信号的器件,通常用于长距离直连线材无法满足传输要求的情况,一般是为了确保信号长距离无衰减的传输而设计,因此多是有源的。我们在使用信号延长器的过程中难免会遇到各种各样的故障问题,那么我们该如何解决呢&…

一文读懂视频监控系统全过程内容

视频监控系统由实时控制系统、监视系统及管理信息系统组成。视频监控系统是安全防范系统的组成部分,它是一种防范能力较强的综合系统。视频监控以其直观、方便、信息内容丰富而广泛应用于许多场合。接下来就由飞畅科技来为大家详细介绍下视频监控系统的全过程&#…

以太网识别标准及接线标准、接线方法详解

以太网是目前应用最普遍的局域网技术,取代了其他局域网技术如令牌环、FDDI和ARCNET。为了使网络系统中的软硬件设备不受生产厂家和型号等不同的限制,制定了各种各样的标准来保证他们之间的相互通,以太网标准就是其中之一,IEEE组织…

Spring Framework中的作用域代理

Spring框架提供了Spring bean的作用域。 我们可以使用spring范围控制插入Spring bean的各种依赖关系和配置值。 Spring支持以下六个范围。 在基于Web的应用程序中可以使用六个中的四个: 范围 描述 辛格尔顿 它是Spring框架中的默认范围。 对于每个Spring IOC容…

中继器、集线器、网桥、网关产品介绍

在了解通信原理之前,我们首先要对通信常用的设备进行熟悉,计算机网络体系中,有几样通信设备或者说网络名词出现的频率相当高,它们是:中继器、集线器、网桥、交换机、路由器和网关。其实,弄清楚这几个计算机…

串口转换器的工作方式及通讯模式介绍

串口转换器能让您在配有RS-232的系统上使用RS-422及RS-485。它透明地将RS-232信号转成隔离的RS-422或RS-485信号。对此,您无需改变PC机任何的硬件或软件就能让您利用标准的PC硬件,来轻松构建一个工业级的长距离通信系统;基于TCP/IP和RS-485/4…

java8根据某个id删选_Java 8可选:如何使用它

java8根据某个id删选Java 8带有新的Optional类型,类似于其他语言中可用的类型。 这篇文章将介绍这种新类型的使用方式,即主要用途。 什么是可选类型? 可选的是新容器类型,如果有可用值,则该容器类型将包装单个值。 因…

Java中的瞬态关键字及其使用

最近,我在一个朋友的一个研究项目中遇到了十字架,他们正在学习Java编程的基础知识,一些忘记的敏感信息打印在文本文件中,并记住了Java中的瞬时关键字。 Java中的瞬时关键字在安全性方面起着重要作用,并且在上述类似的…

RS-232/E1协议转换器产品介绍

RS-232/E1协议转换器是我公司自主研发生产的高性能产品,它将透明E1转换为V.35或者RS232的异步数据接口的接口转换设备,本设备V.35接口可以连接DCE或DTE两种工作方式的设备,RS232接口只支持异步RS232数据,可支持的最高异步速率为11…

java ee cdi_Java EE CDI限定词:快速浏览

java ee cdi在上下文和依赖注入(CDI)中, 限定符是类型安全和松散耦合的主体。 为什么? 没有CDI,我们将以类似于下面的方式注入Java EE组件 注意:这实际上不会编译,只是假设的代码片段 例子1 …

什么是串口协议转换器?串口转换器有哪些特点?

串口转换器是为RS-232/485/422到TCP/IP之间完成数据转换的通讯接口转换器。通过作为服务器端,提供RS-232/485/422终端串口与TCP/IP网络的数据双向透明传输,提供串口转网络功能,RS-232/485/422转网络的解决方案,可以让串口设备立即…

485转232转换器产品介绍及性能参数介绍

配有不同标准串行接口的计算机、外部设备或智能仪器之间进行远程数据通信,需要进行标准串行接口的相互转换。485转换器将单端的RS-232信号转换为平衡差分的RS-485或RS-422信号。RS-485、RS-422自动识别功能,使用更加简单。接下来我们就来为大家详细介绍下…

什么是RS232/RS485转换器?

485转以太网提供串口转网络功能,能够将RS-232/485/422串口转换成TCP/IP网络接口,实现RS-232/485/422串口与TCP/IP网络接口的数据双向透明传输。使得串口设备能够立即具备TCP/IP网络接口功能,连接网络进行数据通信,极大的扩展串口设…

apache jmx_用于JMX访问的Apache Ant任务

apache jmx我想从Ant任务中调用JMX操作。 但是,找到可用的蚂蚁任务库及其用法非常棘手。 因此,让我分享我的经验,使他人更轻松。 JMX操作的Ant任务 我决定遵循Tomcat文档,并使用与tomcat一起分发的ant任务。 仅作记录用途&#…