对于双检锁,其实有多种不同的用法,有很多种用法是无论如何不会出现问题的.
我最初用双检锁来获取jndi对象时,立即有人告诉我双检锁是不安全的,我笑着告诉他:是否安全
我比你更有把握.
static DataSource ds = null;
public static DataSource getDataSource(){
if(ds == null){
synchronized(XXX.class){
if(ds == null)
ds = xxx;
}
}
return ds;
}
这样的DCL有什么安全问题呢?它仅仅是为了不做重复的劳动.一是ds本身是已经存在的对象,不是动态
构造的,二是即使多次获取它也还是同一引用.这里做的工作仅仅是不想让另一个线程多做在JNDI上再查
找一次的工作,因为查找本身是耗时的,与其让另一个线程再查找还不如把它阻塞在synchronized外面什
么也不做.事实上即使是再查找一次两次获得的还是相同的引用,而且是已经构造好,不存在初始化问题
的对象.DCL会有什么安全问题?
所以不要一看到双检锁就认为它有安全问题.有些时候它完全可以非常好地工作.只是你要理解它的安全
问题到底在哪儿?
DCL到底有什么问题?
DCL的安全性最初被公开的时候在2001年JavaWorld.其实那个例子在那个时候已经是错误的.影响了后面几
代人都跟着错误.有时候我甚至不敢相信一些非常简单的问题因为放在权威的地方就没有人敢去责疑.
最初的问题提出者在这儿:http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html
例子是:
class SomeClass {
private Resource resource = null;
public Resource getResource() {
if (resource == null) {
synchronized {
if (resource == null)
resource = new Resource();
}
}
return resource;
}
}
我不知道提这个问题的人是否是个老古董.在2001年,JVM1.2已经发布好久了.JMM(Java Memory Model)已经
已经发布了新的规范,竟然在这个时候提出这样的问题.而且这个已经不存在的问题在此后的五年(今年是2006年)
中一误导着很多人,甚至是一些博士.
这个问题的提出者是这样说的.当一个线程运行到resource = new Resource();时,因为new一个对象需要分配空
间,初始化字段,调用构造方法.当为resource分配好空间后,外面的其它线程就可以看到不为null的resource,而这
时有可能还没有初始化字段和调用构造方法就被其它线程引用了.
确实,在JAVA2(以jdk1.2开始)以前对于实例字段是直接在主储区读写的.所以当一个线程对resource进行分配空间,
初始化和调用构造方法时,可能在其它线程中分配空间动作可见了,而初始化和调用构造方法还没有完成.
但是从JAVA2以后,JMM发生了根本的改变,分配空间,初始化,调用构造方法只会在线程的工作存储区完成,在没有
向主存储区复制赋值时,其它线程绝对不可能见到这个过程.而这个字段复制到主存区的过程,更不会有分配空间后
没有初始化或没有调用构造方法的可能.在JAVA中,一切都是按引用的值复制的.向主存储区同步其实就是把线程工作
存储区的这个已经构造好的对象有压缩堆地址值COPY给主存储区的那个变量.这个过程对于其它线程,要么是resource
为null,要么是完整的对象.绝对不会把一个已经分配空间却没有构造好的对象让其它线程可见.
至于不同线程如何看到另一个线程对实例字段的改变,可以参看我的另一篇文章:深入理解JMM.
那么上面的例子是否有问题?
我可以负责地说,在JVM1.2以后,上面的例子没有问题.(也许还是有问题但以我的水平还没有发现,但绝对不是JW上提
出的那样的问题,那个问题只在1.2以前出现,而2001年早已不是jdk1.1的时代了),很多时候我们需要有独立的思考,
当你觉得你获取一个新知识点时你一定要弄清它存在的环境.
那么到底DCL是否真的就没有问题了呢?
否,现在的问题还是可见性问题,但问题转到了同一对象不同字段上面,这个问题已经在以前说过了:
public MyObject{
private static MyObect obj;
private Date d = new Data();
public Data getD(){return this.d;}
public static MyObect getInstance(){
if(obj == null){
synchronized(MyObect .class){
if(obj == null)
obj = new MyObject();//这里
}
}
return obj;
}
}
一个线程A运行到"这里"时,对于A的工作区中,肯定已经产生一个MyObect对象,而且这时这个对象已经
完成了Data d.现在线程A调用时间到,执行权被切换到另一个线程B来执行,会有什么问题呢?
如果obj不为null,线程B获得了一个obj,但可能obj.getD()却还没有初始化.
为什么?既然obj已经可见了(线程A还没有离开同步块),而d却不可见呢?
如果d不可见,那么obj也应该为null啊?线程B应该等待A释放同步块啊?
事实上,对于"这里"这条语句,线程A还没有离开同步块.
因为没有"离开同步块"这个条件,线程a的工作区没有强制与主存储器同步,这时工作区中有两个字段
obj,d 到底先把谁同步到主存储区,没有条件限制,虽然在线程A的工作区obj和d都是完整的,但有JSL
没有强制不允许先把obj映射到主存储区,如果哪个jvm实现按它的优化方案先把工作存储器中的obj
同步到主存储器了,这时正好线程B获取了,而d却没有同步过去,那么线程B就获取了obj的引用却找不能
obj.getD();
我们发现,其实对于安全性问题都是基于即时构造对象这样的条件下的.如果你把DCL用来控制其它不重
复操作,它就不会出现这样的问题,就象上面从JNDI中查找DataSource,因为查找本身是耗时的,所以我用
DCL来控制"查找"这个行为而不是控制对象本身.其实还有很多可以正确应用DCL的地方.象JLive,OFBiz
这些开源项目中都在大量应用DCL,当然我不是推荐大家都去用DCL,而是如果需要而且合适就去用.有些
问题可以用其它方法来代替.只要你能真正明白它在什么时候是不安全的,你就可以安全地使用DCL.
分享到:
相关推荐
这个实验通过实际操作,使我们深入理解了SQL的DCL语句在权限管理中的应用。GRANT和REVOKE语句是数据库管理员控制数据访问权限的关键工具,它们确保了只有授权的用户才能执行特定的操作,从而保护了数据库的完整性和...
实验七《数据的安全性》是针对数据库原理课程的一个实践环节,旨在帮助学生深入理解数据安全性的重要性和实际操作方法。在这个实验中,主要涉及的是SQL Server数据库管理系统中的安全机制,包括四个层面的防御策略:...
在数据库管理系统(DBMS)中,数据控制语言(DCL)是一组用于管理和控制数据库安全性的SQL命令集合。本篇文章将深入探讨MySQL中的DCL权限控制操作,包括如何创建新用户、授予与撤销用户的权限等。掌握这些操作对于确保...
标题“PKWARE_DCL_fortyuht_zip_pkware_”提到了PKWARE Data Compression Library,这是一款由PKWARE公司开发的...通过深入理解和使用PKWARE DCL,开发者可以提升其项目的数据处理能力,同时确保数据的安全和兼容性。
总的来说,这篇文章通过实例和分析,揭示了Java DCL模式的一些常见误解,并强调了深入理解JMM对于开发高效、可靠的并发代码的重要性。通过这种方式,开发者可以更好地掌握如何在多线程环境中正确地实现单例模式。
通过DCL,数据库管理员可以有效地管理用户的登录、权限分配和撤销等操作,确保数据的安全性和完整性。本篇文章将详细介绍MySQL中的DCL用户管理操作,包括创建、修改、删除用户以及权限的授予与撤销。 #### 二、创建...
MySQL提供了多种安全机制,包括SQLMode的配置,通过调整这些设置可以加强SQL语句的安全性,例如避免数据类型的隐式转换。 在存储引擎方面,MySQL支持多种存储引擎,比如MyISAM、InnoDB、Memory等。每种存储引擎都有...
- **视图**:视图是基于一个或多个表的结果集的虚拟表,它可以简化复杂查询,同时提高数据的安全性。 - **触发器**:触发器是一种特殊类型的存储过程,它可以在特定事件发生时自动执行,如插入、更新或删除记录。 #...
实验的主要目的是让学生深入理解数据安全性,并掌握SQL Server中关于用户、角色和权限管理的方法。以下是实验内容的详细阐述: 1. **Windows NT的网络安全**: - 在Windows NT环境中,网络管理员负责创建用户组,...
在选择和使用电磁炉时,消费者应关注其能效比、安全性、操作简便性等因素。46R12A型号的电磁炉,如果具备优秀的热效率和智能化控制,无疑会提供优质的烹饪体验。同时,了解电磁炉的工作原理和维护知识,能够帮助用户...
此外,了解电磁炉控制程序的开发,不仅有助于我们理解其工作原理,也为DIY爱好者提供了宝贵的参考资料。通过学习这份资料,读者不仅可以提升自己的编程技能,还能掌握家用电器控制系统的开发流程,为未来可能的项目...
4. **安全性**:认证、授权、加密、防火墙等安全机制,保护系统免受攻击。 5. **性能监控**:如何使用工具监测系统性能,及时发现并解决问题。 6. **设计原则**:例如单一职责原则、开闭原则、依赖倒置原则等,指导...
通过这四个实验,学生不仅掌握了SQL Server的基础操作,还对数据库设计原则和实践有了深入理解。实验过程中的每个步骤都是为了提升学生在实际工作中设计和管理数据库的能力。通过这些实践经验,学生将能够更好地应对...
6. **安全性管理**:理解Oracle的角色、权限和对象权限,以及如何通过DBA账户管理用户访问,是保证数据库安全的关键。此外,了解审计功能和加密技术也是保障数据安全的重要部分。 7. **故障诊断与案例分析**:书中...
Java单例模式是一种设计模式,它允许...以上就是关于Java单例模式的深入理解和常见实现方式,希望对你理解单例模式有所帮助。在实际开发中,灵活运用并结合具体场景选择合适的单例模式将有助于提高代码质量和可维护性。
**DCL(数据控制语言)**主要用于权限管理和数据库的安全性,包括: 1. **GRANT**: 授予用户或角色访问数据库对象的权限。 2. **REVOKE**: 撤销已经授予的权限。 3. **COMMIT**: 提交事务,使得事务中的所有更改...
书中内容覆盖了SQL的最新标准,致力于帮助读者建立起对SQL的深入理解和应用能力。 SQL(Structured Query Language)即结构化查询语言,是一种用于存取和操作数据库的标准编程语言。SQL是数据库行业的标准语言,...
标题中的"DCL.rar_PIC 电磁炉_pic电磁炉_电磁炉_电磁炉 程序_电磁炉程序"表明这是一个关于使用PIC单片机进行...通过阅读和分析源代码,我们可以深入理解嵌入式系统在家电中的应用,提升自己的硬件控制和软件开发能力。
2. SQL语言深入:深入探讨SQL语句的编写,包括高级查询技巧、数据操作语言(DML)、数据定义语言(DDL)、数据控制语言(DCL)及事务控制。 3. PL/SQL编程:介绍PL/SQL的基本语法、存储过程、函数、包、触发器等,以及...