快速业务通道

Java模式设计之单例模式(四) - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-22
下面没有使用任何线程安全考虑的错误例子。

从单线程的程序谈起

首先考虑一个单线程的版本。

代码清单13:没有使用任何线程安全措施的一个例子

// Single threaded version class Foo {   private Helper helper = null;   public Helper getHelper()   {    if (helper == null)    {     helper = new Helper();    }    return helper;   }   // other functions and members... }

这是一个错误的例子,详情请见下面的说明。

写出这样的代码,本意显然是要保持在整个JVM 中只有一个Helper 的实例;因此,才会有if (helper == null) 的检查。非常明显的是,如果在多线程的环境中运行,上面的代码会有两个甚至两个以上的Helper 对象被创建出来,从而造成错误。

但是,想像一下在多线程环境中的情形就会发现,如果有两个线程A 和B 几乎同时到达if (helper == null)语句的外面的话,假设线程A 比线程B 早一点点,那么:

(1)A 会首先进入if (helper == null) 块的内部,并开始执行new Helper() 语句。此时,helper 变量仍然是null,直到线程A 的new Helper() 语句返回并给helper 变量赋值为止。

(2) 但是,线程B 并不会在if (helper == null)语句的外面等待,因为此时helper == null 是成立的,它会马上进入if (helper == null)语句块的内部。这样,线程B 会不可避免地执行helper = new Helper();语句,从而创建出第二个实例来。

(3)线程A 的helper = new Helper();语句执行完毕后,helper 变量得到了真实的对象引用,(helper == null)不再为真。第三个线程不会再进入if (helper == null) 语句块的内部了。

(4)线程B 的helper = new Helper(); 语句也执行完毕后,helper 变量的值被覆盖。但是第一个Helper 对象被线程A 引用的事实不会改变。

这时,线程A 和B 各自拥有一个独立的Helper 对象,而这是错误的。

Java模式设计之单例模式(四)(5)

时间:2010-12-14

线程安全的版本

为了克服没有线程安全的缺点,下面给出一个线程安全的例子。

代码清单14:这是一个正确的答案

// Correct multithreaded version class Foo {   private Helper helper = null;   public synchronized Helper getHelper()   {    if (helper == null)    {     helper = new Helper();     return helper;    }   }   // other functions and members... }

显然,由于整个静态工厂方法都是同步化的,因此,不会有两个线程同时进入这个方法。因此,当线程A 和B 作为第一批调用者同时或几乎同时调用此方法时:

(1)早到一点的线程A 会率先进入此方法,同时线程B 会在方法外部等待。

(2) 对线程A 来说,helper 变量的值是null ,因此helper = new Helper(); 语句会被执行。

(3)线程A 结束对方法的执行,helper 变量的值不再是null。

(4)线程B 进入此方法,helper 变量的值不再是null ,因此helper = new Helper(); 语句不会被执行。线程B 取到的是helper 变量所含有的引用,也就是对线程A 所创立的Helper 实例的引用。

显然,线程A 和B 持有同一个Helper 实例,这是正确的。

画蛇添足的“双重检查”

但是,仔细审察上面的正确答案会发现,同步化实际上只在helper 变量第一次被赋值之前才有用。在helper 变量有了值以后,同步化实际上变成了一个不必要的瓶颈。如果能有一个方法去掉这个小小的额外开销,不是更加完美了吗?因此,就有了下面这个设计“巧妙”的双重检查成例。在读者向下继续读之前,有必要提醒一句:正如本小节的标题所标明的那样,这是一个反面教材,因为双重检查成例在Java 编译器里无法实现。

代码清单15:使用双重检查成例的懒汉式单例模式

// Brok

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号