单例模式 指令重排_php单例模式

单例模式 指令重排_php单例模式单例模式写法有很多,于是我看到了这么一种写法:publicclassSingletonTest{privateSingletonTest(){}privatestaticSingletonTestsingletonTest=null;publicstaticSingletonTestgetSingletonTest()…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

单例模式写法有很多,于是我看到了这么一种写法:

public class SingletonTest {

    private SingletonTest() {
    }

    private static SingletonTest singletonTest = null;

    public static SingletonTest getSingletonTest() {
        if (singletonTest == null) {
            // 若singletonTest为空,则加锁,再进一步判空
            synchronized (SingletonTest.class) {
                // 再判断一次是否为null
                if (singletonTest == null) {
                    //若为空,则创建一个新的实例
                    singletonTest = new SingletonTest();
                }
            }
        }
        return SingletonTest;
    }
}

这种写法算是一个考虑比较得当的设计了 为了防止多线程调用产生多个实例,采用了同步锁 加锁位置得当,尽可能降低了加锁对性能的影响 
但是在这个示例下方,有指出可能会由于指令重排的影响,导致代码执行错误,只是概率很低。

 

我不由得重新审视着这段代码,难道看似稳的一逼的代码如此不堪一击? 
于是,我大致了解了下指令重排: 
指令重排序是JVM为了优化指令,提高程序运行效率,在不影响单线程程序执行结果的前提下,尽可能地提高并行度。 
也就是说,JVM为了执行效率会将指令进行重新排序,但是这种重新排序不会对单线程程序产生影响。

首先,JVM是如何保证单线程下的指令在重新排序后执行结果不受影响的呢?

(此处省略一万字……关于happens-before,感兴趣的请看原文)

 由于singletonTest = new SingletonTest()操作并不是一个原子性指令,会被分为多个指令:

memory = allocate(); //1:分配对象的内存空间
ctorInstance(memory); //2:初始化对象
instance = memory; //3:设置instance指向刚分配的内存地址

但是经过重排序后如下:

memory = allocate(); //1:分配对象的内存空间
instance = memory; //3:设置instance指向刚分配的内存地址,此时对象还没被初始化
ctorInstance(memory); //2:初始化对象

 若有A线程进行完重排后的第二步,且未执行初始化对象。此时B线程来取singletonTest时,发现singletonTest不为空,于是便返回该值,但由于没有初始化完该对象,此时返回的对象是有问题的。这也就是为什么说看似稳的一逼的代码,实则不堪一击。 
另外,在《java并发编程实战》16.2.4中对该种双重检查加锁(DCL)提出了批评。批评的主要点在于,该方式会导致上述指出的取到一个无效或错误状态的对象。 
上述代码的改进方法:将singletonTest声明为volatile类型即可(volatile有内存屏障的功能)。

参考博客: https://www.cnblogs.com/senlinyang/p/7875458.html

 

 

节选自:https://blog.csdn.net/yuruixin_china/article/details/80550209

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/180992.html原文链接:https://javaforall.net

(0)
上一篇 2022年10月17日 下午2:36
下一篇 2022年10月17日 下午2:36


相关推荐

  • 龙虾OpenClaw对普通人有什么机会?

    龙虾OpenClaw对普通人有什么机会?

    2026年3月12日
    1
  • Centos7安装mysql+keepalived 高可用环境[通俗易懂]

    Centos7安装mysql+keepalived 高可用环境[通俗易懂]一、环境准备1.节点信息节点IP 节点名称 系统 软件及版本 192.168.51.187 node187 CentOS7 keepalived-1.3.5 mysql-5.7.24 192.168.51.226 node226 CentOS7 2.虚拟VIP虚拟VIP 192.168.51.170 3.初始化,在两个节点上进行常用工具的安装yuminstallgccgcc…

    2022年6月6日
    45
  • gis地理加权回归步骤_地理加权回归权重

    gis地理加权回归步骤_地理加权回归权重内容导读1)回归概念介绍;2)探索性回归工具(解释变量的选择)使用;3)广义线性回归工具(GLR)使用;*加更:广义线性回归工具的补充内容4)地理加权回归工具(GWR)使用+小结。说明:本节是这个学习笔记最后一部分。PART/04地理加权回归工具(GWR)使用上一节我们讲了GLR广义线性回归,它是一种全局模型,可以构造出最佳描述研究区域中整体数据关系的方程。如果这些关系在研究区域中是一致的,则GLR回归方程可以对这些关系进行很好的建模。不过,当这些关系在研

    2022年10月6日
    8
  • ubuntu安装搜狗输入法后黑屏_乌班图如何安装搜狗输入法

    ubuntu安装搜狗输入法后黑屏_乌班图如何安装搜狗输入法1、ubuntu系统配置systemsettings->languagesupport->install/removelanguages,在弹出的菜单中选择Chinese(simplified),点击apply2、配置输入法框架搜狗输入法是建立在fcitx框架之上的,所以要将输入法框架选择为fictx,注意:如果没有fcitx选项,那么你就需…

    2026年4月14日
    7
  • 教你写一手漂亮的伪代码(详细规则&简单实例)

    教你写一手漂亮的伪代码(详细规则&简单实例)文章目录前言伪代码的 7 个主要部分 1 算法名称 2 指令序列 3 输入 输出 4 分支选择 5 赋值 6 循环 7 算法结束补充举个例子说明前言最近在复盘 算法设计与分析 这门课程的时候 发现老师写得一手漂亮的伪代码 着实羡慕不已 看他写其实已经知道大致写伪代码的规则 但本着严谨的态度 还是系统的学习和整理出来 在学习过程中 我们不可能将每一个算法都完完整整敲一遍 那么伪代码就可以很快捷和清晰的写出对一个算法的解决思路 我在网上查到的博客中要么写的过于繁琐 要么就是没有实例 这也激起了我想要整理这篇文章的动力 若文

    2026年3月18日
    2
  • 2021.5iDea激活码[在线序列号]

    2021.5iDea激活码[在线序列号],https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月19日
    45

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号