单例模式singleton为什么要加volatile_为什么要在变量singleton之间加上volatile-程序员宅基地

技术标签: singleton  指令重排序  volatile  为什么要加  设计模式  

或者许多的朋友在使用单例模式中会学到双重检查加锁(double-checked locking)的应用。

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

但同时也会产生一个问题:为什么要用到volatile。这里不妨先看看一牛人对于volatile关键字的解读。
作者:海子
    
出处:http://www.cnblogs.com/dolphin0520/p/3920373.html
    
看完volatile之后,你就可以对于指令重排序有进一步的了解后,尤其是volatile可以保证即使java虚拟机对代码执行了指令重排序,也会保证它的正确性。
然后我们来指出下为什么用了synchronized还要用volatile,以及可能出现的指令重排序影响双重检查加锁(double-checked locking)的正确性。
可以看以下例子。

public class Singleton {
    private volatile static Singleton uniqueInstance;
    private Singleton(){}
    public static Singleton getInstance(){
        if(uniqueInstance == null){
        // B线程检测到uniqueInstance不为空
            synchronized(Singleton.class){
                if(uniqueInstance == null){
                    uniqueInstance = new Singleton();
                    // A线程被指令重排了,刚好先赋值了;但还没执行完构造函数。
                }
            }
        }
        return uniqueInstance;// 后面B线程执行时将引发:对象尚未初始化错误。
    }
}

具体来说就是synchronized虽然保证了原子性,但却没有保证指令重排序的正确性,会出现A线程执行初始化,但可能因为构造函数里面的操作太多了,所以A线程的uniqueInstance实例还没有造出来,但已经被赋值了。而B线程这时过来了,错以为uniqueInstance已经被实例化出来,一用才发现uniqueInstance尚未被初始化。要知道我们的线程虽然可以保证原子性,但程序可能是在多核CPU上执行。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jm_heiyeqishi/article/details/51052889

智能推荐

GDAL:创建矢量线、矢量面数据_gdal创建面-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏26次。分享给有需要的人,代码质量勿喷。一、创建矢量线数据 单个要素 void xjCreateVectorLineByGDAL(QList<xjPoint> ListNode, const QString &xjSavePath) { GDALAllRegister(); OGRRegisterAll(); const char *xjDriverName =..._gdal创建面

MATLAB01:基本的数学运算与矩阵运算_matrixxd 赋值-程序员宅基地

文章浏览阅读10w+次,点赞1.6k次,收藏3.9k次。MATLAB01:基本的数学运算与矩阵运算MATLAB基本语法变量变量名保留变量不适合做变量名变量不应当覆盖内置函数MATLAB的调用优先级变量类型数字型变量的显示格式MATLAB命令行使用MATLAB进行数字运算使用MATLAB计算数学表达式MATLAB内置的数学函数使用MATLAB进行矩阵运算定义矩阵向终端输入矩阵使用冒号运算符创建向量定义特殊矩阵矩阵的索引矩阵的操作操作矩阵的运算符操作矩阵的..._matrixxd 赋值

ADC驱动开发-程序员宅基地

文章浏览阅读292次,点赞4次,收藏5次。两片ADC,需要时钟,始终来源与时钟选择芯片,选择外部时钟源或者HMC830的输出时钟,外部时钟源是由铷钟授时卡提供。两片ADC,需要时钟,始终来源与时钟选择芯片,选择外部时钟源或者HMC830的输出时钟,外部时钟源是由铷钟授时卡提供。看原理图——找ADC的时钟——时钟是怎么来的——时钟选择芯片,时钟扇出BUF——外部时钟源或HMC830的输出时钟。看原理图——找ADC的时钟——时钟是怎么来的——时钟选择芯片,时钟扇出BUF——外部时钟源或HMC830的输出时钟。

Java教学团队管理系统(开题+源码)-程序员宅基地

文章浏览阅读22次。本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。教学团队管理系统:研究背景、意义与目的随着教育环境的日益复杂化,教学团队管理系统的重要性日益凸显。传统的教学管理方式已经无法满足现代教育的需求,这主要表现在对教师资源的管理、课程的安排以及教学团队的协作等方面。因此,一个高效、便捷、易用的教学团队管理系统变得十分必要。研究背景:在现有的教育环境中,教学团队管理系统的需求日益增长。然而,目前的教学团队管理系统仍存在诸多问题,如教师资源的分配不均,课程的安排不合理,以及教学团

photoshop 导出 qml脚本问题(问题解决)_photoshop怎么转为qt的qml-程序员宅基地

文章浏览阅读2.2k次。2012-02-29 16:33Photoshop在从8.0到cs 4的发展中对脚本的支持越来完善,而致力于为移动平台打造更流畅、更易于开发的Qt新框架——QtQuick也日渐成熟。而QtQuick的核心之一就是QML语言。至此,gemfield本文题目中的两个名词全都出现了。下面gemfield详细说说。关于QML的一些基本元素在CivilNet社区的相关版块中已_photoshop怎么转为qt的qml

var、let、const的区别(超详细易懂)_var let const的区别-程序员宅基地

文章浏览阅读1.6w次,点赞72次,收藏401次。var、let、const的区别_var let const的区别

随便推点

CSS基础(超详解)-程序员宅基地

文章浏览阅读2.3w次,点赞103次,收藏800次。Css (层叠样式表)是种格式化网页的标准方式, 用于控制设置网页的样式,并且允许CSS样式信息与网页内容(由HTML语言定义)分离的一种技术。_css

Android 百度地图SDK 自动定位、标记定位_安卓开发地图获取定位-程序员宅基地

文章浏览阅读1.2w次,点赞98次,收藏201次。先看效果图,如果不是你想要的,也就不浪费你时间了,这样对大家都好。如果是你满意的那样,我们就可以开始写了,首先创建一个名为MapDemo的项目。打开AndroidManifest.xml,复制你的包名然后进入百度地图开放平台,没有注册的小伙伴先注册,已注册的就直接登录,登录进去之后找到控制台→我的应用→创建应用点击之后进入,填写相关资料输入了应用名称、选择了应用类型和启用的服务,输入了包名。还差开发版和发布版的SHA1了① 获取开发版SHA1鼠标点击右侧边栏的Gradle→ app→Ta_安卓开发地图获取定位

java特殊字符转html_html特殊字符转换(java)-程序员宅基地

文章浏览阅读431次。/** * 把文本编码为Html代码 * @param target * @return 编码后的字符串 */ public static String htmEncode(String target) { StringBuffer stringbuffer = new StringBuffer(); int ...

尚硅谷最新版JavaScript基础全套教程完整版(p48-p65)_尚硅谷javascript新书大纲-程序员宅基地

文章浏览阅读237次。尚硅谷最新版JavaScript基础全套教程完整版(140集实战教学,JS从入门到精通)一、基本数据类型和引用数据类型1.基本数据类型-string 、 number 、 Boolean 、null 、undefined2.引用数据类型-object3.区别-JS中的变量都是保存到栈内存中的,基本数据类型的值直接在栈内存中存储,值与值之间是独立存在的,修改一个变量不会影响另外一个变量。-引用数据类型(对象)是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,而变量保存_尚硅谷javascript新书大纲

ACM--HDOJ 2072--单词数--字符串--水_java acm单词数问题 #结束-程序员宅基地

文章浏览阅读1.2k次。HDOJ题目地址:传送门单词数Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 44934 Accepted Submission(s): 10992Problem Descr_java acm单词数问题 #结束

uniapp自定义tabbar必看_uniapp custom-tab-bar-程序员宅基地

文章浏览阅读9.5k次。方式一:实验证明,在根目录下新建custom-tab-bar目录,在目录中新建index.vue是行不通的,vue文件不会被编译方式二:将小程序四大法宝(wxss,json,wxml,js)直接搬过来,虽然tabbar有渲染在小程序上了,但是切换是没有效果的,所以还是行不通方式三(行得通)经过上面的两个尝试,还是乖乖的以vue的做法吧,用单页面的形式,通过v-show控制组件的隐藏和显示注意:v-show有时没有效果,因为v-show是通过display:none来控制的,它的权重没_uniapp custom-tab-bar

推荐文章

热门文章

相关标签