首先必须声明,
在volatile出现之前,错误的DCL代码如下。在volatile出现之后,正确的DCL代码如下。代码如下:
//错误的代码
public class Singleton {
private static Singleton instance=null;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class) {
if(instance==null)
instance=new Singleton();//mark行
}
}
return instance;
}
}
//正确的代码
public class Singleton {
private volatile static Singleton instance=null;//添加了volatile修饰符
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class) {
if(instance==null)
instance=new Singleton();
}
}
return instance;
}
}
我们来剖析错误的代码:
在错误的DCL代码中,代码行mark在JVM中有2种可能的执行顺序(JVM会对一些没有依赖要求的指令重排序。
关于重排序,在下文中进行说明),分别为:
//第一种执行顺序
mem=allocate()
mem.initial()
instance=mem
//第二种执行顺序
mem=allocate()
instance=mem
mem.initial()
假设现在有2个线程a和b,线程a执行到mark行语句并按照第二种执行顺序执行完instance=mem指令。此时线程b执行getInstane方法会直接返回一个非空的instance,但是这个instance可能是未被完整创建的。这个时候,DCL就出问题了。这就是大家对DCL口诛笔伐的原因。由此可见,
错误的DCL的真正问题就在于:在没有同步的情况下读取一个共享变量,可能读到不完整的实例。也就是说,不在同步代码块中的if(instance==null)代码可能读取到不完整的instance实例。
为了解决类似DCL中出现的问题,
JAVA在JMM中(JAVA内存模型)定义了一系列Happens-Before关系。如果两个操作之间缺少Happens-Before关系,那么JVM就可以对它们任意的重排序。比如volatile变量规则规定:对volatile变量的写入操作必须在对该变量的读操作之前进行。这就是DCL在使用volatile之后变得正确的原因。
重排序:
下面的代码可能的输出结果有:<1,1><1,0><0,1><0,0>这四种,首先,两个线程的先后执行顺序不同,可能one先(结果是<0,1>),可能two先(结果是<1,0>),可能one和two交替执行(结果是<1,1>);其次,由于每个线程内部的各个操作之间不存在依赖性,因此这些操作可以重排序(结果可能为<0,0>)。可见,
内存级别的重排序会令程序变得不可预测,因此需要正确的使用同步,以使程序满足JMM要求的可见性规则。
public class Demo{
static int x=0,y=0;
static int a=0,b=0;
public static void main(String [] args) throws InterruptedException {
Thread one=new Thread(new Runnable() {
@Override
public void run() {
a=1;
x=b;
}
});
Thread two=new Thread(new Runnable() {
@Override
public void run() {
b=1;
y=a;
}
});
one.start(); two.start();
one.join(); two.join();
System.out.println("<"+x+","+y+">");
}
}
分享到:
相关推荐
the oracle of the DDL, DML, DCL and TCL Category
描写autoCAD dcl语言的一本比较牛的书
一个单例模式的晋级过程(饿汉-懒汉-DCL-IoDH-枚举) 文章目录一个单例模式的晋级过程(饿汉-懒汉-DCL-IoDH-枚举)什么是单例?单例有哪些运用场景?实现1.饿汉式测试优化-final2.懒汉式优化-加锁同步3.DCL双检锁/双重...
soal1-dcl
DCL语句主要是DBA用来管理系统中的对象权限时使用,一般的开发人员很少使用,下面通过一个例子简单说明一下。由于权限呢变更,需要将z1的权限变更,收回INSERT,只能对数据进行SELECT操作:用户z1重新登录后执行前面...
DML(Data Manipulation Language)语句数据操纵语句,用于添加、删除、更新和查询数据库记录,并检查数据完整性,常用的语句关键字主要包括
`1111111111111111111111111111111111111111111
18. 基础-SQL-DCL-用户管理- 19. 基础-SQL-DCL-权限控制- 20. 基础-函数-字符串函数 21. 基础-函数-数值函数 22. 基础-函数-日期函数 23. 基础-函数-流程函数 24. 基础-约束-概述 25. 基础-约束-演示 26. 基础-约束-...
SQLPLUSSYSASSYSDBA;...例如:CONNLAOSAN/LAOSAN;ORACLE的表空间分了几种类型,临时表空间[TEMPFILE],用户表空间 [DATAFILE],大文件表空间[BIGFILE]等,创建表空间,一般都是DBA干的事情。SIZE*[K,M]表空间的初始大小...
Create React App入门该项目是通过。可用脚本在项目目录中,可以运行:yarn start 在开发模式下运行应用程序。 打开在浏览器中查看。 如果进行编辑,页面将重新加载。 您还将在控制台中看到任何棉绒错误。...
这项工作由气候计划办公室的国家海洋与大气管理局合同NA18OAR4310408资助。 我们要感谢国家科学基金会(National Science Foundation)赞助的NCAR计算和信息系统实验室提供的夏安( )高性能计算支持。 该材料基于...
DCL-202:Java SE 8编程 这些项目是作为以下培训的一部分而创建的:DCL-202“ Java SE 8编程” 请点击完整培训目录的链接: : 库鲁鲁姆·比尔吉西(Kurulum Bilgisi): Eğitimde实验室çalışmalarıICIN ...
用VB的Form直接生成DCL对话框程序极其调用的LSP文件 能自动对DCL对话框中的参数进行读取和赋值,并输出 使用步骤: 一、在VB中绘制好表单Form 注意:排列的时候尽量一行的Top坐标相同,这样能保证在同一行 二、将...
DCL-350:使用Spring Cloud实施MicroService体系结构这些项目是作为以下培训的一部分而创建的:DCL-350:使用Spring Cloud实施MicroService体系结构请点击完整培训目录的链接: : Kurulum Bilgisi: Eğitimde实验室...
通过实例程序验证与优化谈谈网上很多对于Java DCL的一些误解以及为何要理解Java内存模型.doc
数据控制语言(DCL-Data-Control-Language)-2(常用版).doc
分析了用AutoCAD内嵌的AutoLISP与DCL整合的开发过程,通过开发表面结构代号绘制工具的实例,说明了利用DCL和AutoLISP能够编写出人机交互强和功能强大的程序,从而对AutoCAD进行有效的二次开发,提高绘图效率,使AutoCAD...
Product Description and Identification (Part Number) ...DCL Series of multi-layer chip inductors for choke. 2) Product Identification (Part Number) DCL ※※※※ 〇 XXX □ ◎ ① ② ③ ④ ⑤ ⑥
饿汉模式、懒汉模式、DCL单例模式、枚举;不同情况下使用不同的单例创建模式