分享
 
 
 

多线程编程 深入理解DCL的安全性

王朝other·作者佚名  2006-08-19
窄屏简体版  字體: |||超大  

对于双检锁,其实有多种不同的用法,有很多种用法是无论如何不会出现问题的.

我最初用双检锁来获取jndi对象时,立即有人告诉我双检锁是不安全的,我笑着告诉他:是否安全

我比你更有把握.

static DataSource ds = null;

public static DataSource getDataSource(){

if(ds == null){

synchronized(this.getClass()){

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.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有