java内存模型-DCL

DCL   

     DCL(Double-Checked Locking)是一种用于实现线程安全的延迟初始化的技术。在Java中,DCL通常用于单例模式的实现。

    DCL的基本思想是通过两次检查锁来实现延迟初始化。在第一次检查时,如果对象已经被初始化了,那么直接返回对象。如果对象尚未被初始化,则进入临界区并获取锁,在临界区中再次检查对象是否被初始化,以确保只有一个线程进行实例化操作。

   单例模式

   DCL- 重排序

        在Java内存模型中,重排序是指编译器和处理器为了提高并行度和性能,可能会对指令的执行顺序进行重新排序。

     在DCL(Double-Checked Locking)单例模式中,为了避免多个线程同时创建实例,我们通常会使用双重检查锁定来实现线程安全的单例模式。

然而,由于重排序的存在,DCL单例模式可能会导致线程安全的问题。

在DCL单例模式中,有以下几个步骤:

  1. 检查实例是否已经创建,如果已经创建则直接返回实例。
  2. 如果实例未创建,则使用同步锁来创建实例。
  3. 创建实例后,再次检查实例是否已经创建,如果已经创建则直接返回实例。

在步骤2和步骤3之间,可能会发生重排序。如果重排序发生,可能会导致多个线程同时进入步骤3,从而创建多个实例。

为了解决这个问题,我们需要使用volatile关键字。在使用volatile关键字修饰实例的引用时,会禁止指令重排序。

使用volatile关键字修饰实例引用后,可以确保在多线程环境下,实例的创建和赋值操作是按照顺序进行的,从而避免了重排序导致的线程安全问题。

下面是一个使用volatile关键字修饰的DCL单例模式的示例代码:

public class Singleton {private volatile static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

     在这个示例代码中,我们使用了volatile关键字修饰了instance,确保了步骤3的操作不会发生重排序。这样就避免了线程安全问题。

   DCL- happens-beofre

         

在Java内存模型中,happens-before原则是指如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。

在DCL(双重检查锁)单例模式中,使用了volatile关键字来保证线程安全。volatile关键字具有禁止指令重排序的作用,因此可以保证在DCL中的两次检查操作之间,初始化操作的结果对其他线程可见。

具体来说,在DCL中的happens-before关系如下:

  1. 在线程A执行DCL的第一个检查操作时,线程A读取到的volatile变量值会反映在该操作之前的所有操作中。
  2. 在线程A执行DCL的第一个检查操作后,如果发现单例对象没有被初始化,线程A会进入同步代码块。在进入同步代码块之前,线程A必须先获取锁。
  3. 在线程A获取到锁之后执行的操作会反映在该操作之前的所有操作中,包括第一个检查操作。
  4. 在线程A执行初始化操作之前,所有线程对该对象的引用都必须被刷新到主存中,以便其他线程能够看到更新后的值。
  5. 在线程A执行初始化操作时,线程A对volatile变量的写入操作会反映在该操作之前的所有操作中。
  6. 在线程A执行初始化操作之后,线程A会释放锁,此时所有对该锁的后续获取操作都必须在该操作之前执行。
  7. 在线程B执行DCL的第一个检查操作时,线程B读取到的volatile变量值会反映在该操作之前的所有操作中。
  8. 在线程B执行DCL的第一个检查操作后,如果发现单例对象已经被初始化,线程B可以直接使用该对象,无需再进入同步代码块。

      通过以上happens-before关系,DCL单例模式可以保证在多线程环境下,只会有一个实例被创建,并且对其他线程可见。

解决方案

   volatile方案

      使用volatile关键字修饰共享变量能够实现如下两个目标:

  1. 禁止指令重排序:在Java内存模型中,编译器和处理器为了性能优化会对指令进行重排序。但是,如果不使用volatile关键字修饰共享变量,就有可能导致指令重排序从而破坏DCL的正确性。
  2. 强制线程从主内存中读取变量:volatile关键字会强制线程从主内存中读取共享变量的值,而不是从工作内存中读取。这样可以确保线程读取到的是最新的变量值。

使用volatile关键字修饰共享变量的DCL实现如下所示:

public class Singleton {private static volatile Singleton instance;private Singleton() {// private constructor}public static Singleton getInstance() {if (instance == null) {  // 第一次检查synchronized (Singleton.class) {if (instance == null) {  // 第二次检查instance = new Singleton();}}}return instance;}
}

       在上述代码中,instance变量使用volatile关键字修饰,确保线程对instance的读写操作在工作内存和主内存之间保持一致。同时,通过双重检查锁定(double-checked locking)来确保只有第一次调用getInstance()方法时才会创建实例。

        需要注意的是,虽然volatile关键字能够解决DCL的一些问题,但并不能完全保证线程安全。实际上,DCL在Java 1.5之前的版本中是无法正确工作的,主要是由于JVM在处理volatile关键字时的实现细节有问题。因此,在Java 1.5之前的版本中,建议使用其他线程安全的单例模式实现方式,如静态内部类单例模式。

   基于类初始化的解决方案

          基于类初始化的解决方案,也称为静态内部类解决方案,是一种解决DCL问题的方法,它利用了Java的类初始化过程的线程安全性。

具体实现如下:

  1. 创建一个私有的静态内部类,该静态内部类持有一个私有静态变量的实例。
public class Singleton {private Singleton() {// 私有化构造方法}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}
  1. 在静态内部类中实例化Singleton对象,并将其赋值给静态变量INSTANCE。

  2. 客户端通过调用Singleton.getInstance()方法来获取Singleton的唯一实例。

      这种基于类初始化的解决方案可以保证线程安全性,因为在Java中,类的静态初始化阶段会由类加载器来保证线程安全性。当SingletonHolder被加载和初始化时,静态变量INSTANCE也会被创建并初始化,类初始化阶段是单线程执行的,因此可以保证 INSTANCE 的唯一性。

     这种解决方案的缺点是在类加载时就实例化了Singleton对象,如果该对象占用较多资源或需要延迟加载,可能会影响应用程序的性能。

   
总结

      DCL(Double-Checked Locking)是一种延迟初始化实例的一种常用模式。其核心思想是,在保证线程安全的前提下,尽可能地减少同步开销,提高程序性能。

在Java内存模型中,使用DCL模式需要注意以下几点:

  1. 使用volatile关键字修饰实例变量,确保可见性:在DCL模式中,需要使用volatile关键字修饰实例变量,以确保不同线程对该变量的可见性。通过使用volatile关键字,可以保证所有线程在访问该变量时都能看到最新的值,从而避免出现不一致的情况。

  2. 加锁保证多线程安全:在DCL模式中,需要使用synchronized关键字对实例的初始化方法进行加锁,以保证多线程环境下的安全性。只有一个线程能够成功获取该锁,其他线程则需要等待。

  3. 双重检查保证实例只被初始化一次:在DCL模式中,使用双重检查的方式保证实例只被初始化一次。首先,通过检查实例是否已经被初始化,避免重复初始化;然后,再通过加锁的方式进行实例的初始化。

  4. 使用局部变量提高性能:在DCL模式中,可以使用局部变量保存已经初始化的实例,避免每次获取实例时都加锁。通过使用局部变量,可以提高程序的性能。

      

     

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

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

相关文章

径流场水土流失自动监测系统的使用

TH-LS1随着环保意识的日益增强,水土流失问题已经成为全球关注的焦点。水土流失不仅破坏了生态环境,还对农业生产、水资源保护等方面产生了严重影响。为了有效监测和控制水土流失,径流场水土流失自动监测系统应运而生。 一、径流场水土流失自…

希尔排序解读

在算法世界中,排序算法是至关重要的一部分。而希尔排序(Shell Sort)作为一种基于插入排序的改进算法,通过允许交换非相邻元素,从而在一定程度上提高了排序效率。本文将深入探讨希尔排序的原理、实现方式以及它的性能特…

.net 实现的 Webscoket 对象的一些细节和疑问

这两天服务器和客户端进行了webscoket的联调,在和C#的webscoket实现联调的过程中,发现一些有趣的事情。 在我自己C的实现中,webscoket对上层应用而言是完全透明的,webscoket 只是一个传输协议,用户对此不需要有任何关…

Linux C++ 023-类模板

Linux C 023-类模板 本节关键字:Linux、C、类模板 相关库函数:getCapacity、getSize 类模板语法 类模板的作用:建立一个通用的类,类中的成员 数据类型可以不具体制定, 用一个虚拟的类型代表语法: templa…

stable diffusion的从安装到使用

stable-diffusion,一个免费开源的文生图软件,文章主要讲怎么从源码开始安装,以及使用的方式 git地址:https://github.com/AUTOMATIC1111/stable-diffusion-webui 本人电脑环境win10,软件pycharm,需要提前…

Java关键字保留字(共53个)

保留字(2个) 保留字(Reserve Word):即它们在Java现有版本中没有特殊含义,以后版本可能会作为有特殊含义的词,或者该词虽然在Java中没有特殊含义,以后版本也不打算使用,但…

jeecg-boot 3.6使用微服务启动详细配置

1:运行sql文件 2:配置host 路径如下 127.0.0.1 jeecg-boot-redis 127.0.0.1 jeecg-boot-mysql 127.0.0.1 jeecg-boot-nacos 127.0.0.1 jeecg-boot-gateway 127.0.0.1 jeecg-boot-system 127.0.0.1 jeecg-boot-xxljob 127.0.0.1 jeecg-boot-rabbitmq 3…

LeetCode第十五题:三数之和【15/1000 python】

👤作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。 会一些的技术:数据分析、算法、SQL、大数据相关、python 作者专栏每日更新: LeetCode解锁1000题: 打怪升级之旅 LeetCode解锁1000题: 打怪升级之旅htt…

gitea详细介绍

Gitea 是一个轻量级、易于安装的 Git 服务,提供了类似于 GitHub 的功能,如代码托管、问题追踪、团队合作等。它使用 Go 语言开发,可以在自己的服务器上进行部署,从而实现自托管的 Git 服务。Gitea 具有用户友好的界面,…

数据研发八股文(1)

数据库 hadoop与spark结构 Hadoop和Spark在结构上都包含了多个核心组件,但它们的具体实现和用途有所不同。 Hadoop的结构主要包括HDFS(Hadoop Distributed File System)和MapReduce。HDFS是一个分布式文件系统,用于存储海量的数据…

【管理咨询宝藏52】AA银行企业文化策略分析报告

本报告首发于公号“管理咨询宝藏”,如需阅读完整版报告内容,请查阅公号“管理咨询宝藏”。 【管理咨询宝藏52】AA银行企业文化策略分析报告 【格式】PPT版本,可编辑 【关键词】战略规划、商业分析、管理咨询 【强烈推荐】这是一套市面上非常…

npm包安装与管理:深入解析命令行工具的全方位操作指南,涵盖脚本执行与包发布流程

npm,全称为Node Package Manager,是专为JavaScript生态系统设计的软件包管理系统,尤其与Node.js平台紧密关联。作为Node.js的默认包管理工具,npm为开发者提供了便捷的方式来安装、共享、分发和管理代码模块。 npm作为JavaScript世…

Unity MySql安装部署与Unity连接 上篇

1.前言 最近项目用到MySql,记录一下安装部署过程。 数据量过大或者需要管理用户数据的时候用mysql的话数据结构比较清晰明了,便于管理。 2.安装MySql Unity版本:2019.4.16 MySql版本:8.2.0 下载地址:MySql 下载…

【数据结构】利用顺序表实现通讯录

文章目录 前言通讯录要求利用顺序表的现有功能代码呈现 前言 这篇文章实现的通讯录利用了笔者上一篇写的有关顺序表的应用 https://blog.csdn.net/2301_77954967/article/details/137360029?spm1001.2014.3001.5502,需要用的朋友自行复制 通讯录要求 1)至少能够…

PostgreSQL入门到实战-第七弹

PostgreSQL入门到实战 PostgreSQL查询语句(四)官网地址PostgreSQL概述PostgreSQL中DISTINCT 语句介绍PostgreSQL中DISTINCT 语句实操更新计划 PostgreSQL查询语句(四) 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https:…

【测试篇】Selenium + Java环境搭建

文章目录 Selenium Java环境搭建配置系统环境变量PATH验证环境是否搭建成功常见问题&解决办法 Selenium Java环境搭建 Java版本最低要求为8,这里默认大家都下载好了Java。😆 下载chrome浏览器(点我下载) 观察chrome版本。…

设备监控公有云

在数字化浪潮的推动下,越来越多的企业开始关注设备监控公有云这一重要领域。设备监控公有云通过云计算技术,实现对设备的远程监控、管理和维护,大大提高了企业的运营效率和管理水平。HiWoo Cloud平台作为领先的设备监控公有云解决方案提供商&…

【数据库】PostgreSQL源码编译安装方式与简单配置(v16.2)

PostgreSQL源码编译安装方式与简单配置(v16.2) 一、PostgreSQL安装基本介绍1.1 几种PostgreSQL的安装方式1.2 删除原有的PostgreSQL1.3 编译安装过程简介 二、源码编译安装方式详情2.1 下载源代码2.2 编译安装运行 configure执行 make执行 make install …

力扣207.课程表

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。 例如…

SSM党员管理系统

一、系统介绍 党员管理系统: 可以方便管理人员对党员管理系统的管理,提高信息管理工作效率及查询效率,有利于更好的为用户提供服务。 主要的模块包括: 1、后台功能: 管理员角色:首页、个人中心,党员管理…