注册 | 登录
收藏 | 帮助
热门文章
编辑推荐
相关文章  
Norton AntiVirus 2005测试版截图
快速有效地封杀—巧利用Iris来查
从Melissa到Zotob:Windows蠕虫1
快速有效地封杀—巧利用Iris来查
IIS的NSIISLOG.DLL溢出问题分析
IIS存在未明远程攻击漏洞
保护(IIS)web服务器的15个技巧
Microsoft AntiSpyware微软出品的
提高操作系统和IIS安全性的绝招
Windows Vista系统防火墙初探
您现在的位置: 顶尖设计 >> IT学院 >> 编程开发 >> VB >> 文章正文
Visual Basic.NET实现双检锁(DCL)模式
作者:佚名  来源:不详  点击:  更新:2006-12-19
简介:

  本文介绍了称为双检锁(Double-Check Locking简称DCL)模式的代码模式,它的工作原理及其在Singleton(单例)模式及Multiton(多例)模式中的应用,并且讨论了DCL模式在Visual Basic.net和C#语言中的实现。其中Visual Basic.NET的源代码可以在文中看到,C#的源代码在附录中给出。

  本文假设读者熟悉Visual Basic.NET或C#的多线程概念、设计模式的基本概念,以及UML基本图标。

  DCL模式(Double-Check Locking Pattern)有时又称作双检模式(Double-Check Pattern),只有在多线程的环境中才有用。它是从C语言移植过来的。在C语言里,DCL模式常常用在多线程环境中类的迟实例化(Late Instantiation)里。

  DCL模式通常与Factory模式一同使用,用来循环使用产品对象。如果读者熟悉 Singleton(Singleton)模式的话,DCL模式可以使用到"懒汉式"的Singleton模式里面,用来提供唯一的产品对象。通过进一步推广,可以使用到Multiton模式和Flyweight模式里面。

  从Factory模式谈起

  为了解释什么是DCL模式,还是从Factory模式谈起吧。

  在下面的类图中,工厂类Factory0有一个共享方法GetInstance()用来提供产品类Product的实例。


图1、一个由工厂类与产品类组成的系统。

  Factory0的源代码如下:


Public Class Factory0
 Public Shared Function GetInstance() As Product
  Return New Product()
 End Function
End Class 代码清单1、Factory0类的源代码

  显然,只要调用GetInstance()方法就会得到Product类的实例,每一次调用得到的都是新的实例。Product类特别提供了计数的方法,通过调用GetCount()方法就可以得到Product所有实例的总数。 Public Class Product
Private Shared count As Integer = 0

Public Sub New()
 count += 1
 System.Console.WriteLine("Product number {0} is created.", count)
End Sub

Public Shared Function GetCount() As Integer
 Return count
 End Function
End Class 代码清单2、产品类Product的源代码

  但是如果产品类的实例必须循环使用,而不能无限制创建的话,工厂方法GetInstance()的内容必须改写,以实现必要的循环逻辑。而最简单的循环逻辑,就是重复使用单一的产品类实例。比如下面的源代码就实现了单一产品类实例的逻辑: Public Class Factory1
Private Shared instance As Product

Public Shared Function GetInstance() As Product
 If (instance Is Nothing) Then
  instance = New Product()
 End If
 Return instance
End Function
End Class 代码清单3、工厂类Factory1的源代码

  简单得不能再简单了吧?如果已经创建过Product类实例的话,就返还这个实例;反之,就首先创建这个实例,将之记录在案,然后再返还它。

  写出这样的代码,本意显然是要保持在整个系统里只有一个Product 的实例;因此才会有 If (instance Is Nothing) Then 的检查。不很明显的是,如果在多线程的环境中运行,上面的代码会有两个甚至两个以上的Product对象被创建出来,从而造成错误。

  在多线程环境里,如果有两个线程A和B几乎同时到达 If (instance Is Nothing) Then语句的外面的话,假设线程A比线程B早一点点,那么:

  1. A会首先进入If (instance Is Nothing) Then 块的内部,并开始执行New Product()语句。至此时,instance变量仍然是Nothing,直到线程A的New Product()语句返回并给instance变量赋值。

  2. 但是,线程B并不会在If (instance Is Nothing) Then 语句的外面等待,因为此时instance Is Nothing是成立的,它会马上进入If (instance Is Nothing) Then语句块的内部。这样,线程B会不可避免地执行instance = New Product()的语句,从而创建出第二个实例来。

  3. 下面,线程A的instance = New Product()语句执行完毕,instance变量得到了真实的对象引用, (instance Is Nothing)不再为真。第三个线程不会在进入If (instance Is Nothing) Then语句块的内部了。

  4. 紧接着,线程B的instance = New Product()语句也执行完毕,instance变量的值被覆盖。但是第一个Product对象被线程A引用的事实不会改变。

  这时,线程A和B各自拥有一个独立的Product对象,而这是错误的。为了能够直观地看到程序执行的结果,可以运行下面的客户端代码: Private Sub Run1()
 Dim o As Product
 o = Factory1.GetInstance
 System.Console.WriteLine("Total number of objects created: {0} ", o.GetCount)
End Sub

Private Sub btnCreate1_Click(…) Handles btnCreate1.Click
 Dim t(9) As Thread
 Dim count As Integer

 For count = 0 To 9
  t(count) = New Thread(AddressOf Run1)
  t(count).Start()
 Next
End Sub 代码清单4、客户端的源代码

  另外在Factory1的GetInstance()方法的第一行加入:

Thread.Sleep(10)

  的语句,相当于模拟一个冗长的产品创建过程,使得最早进入的线程等待后面的线程,从而凸显现多线程的问题。

  上面的客户端代码使用了10个线程同时调用工厂方法,然后调用产品的计数方法,打印出产品类的实例总数。如果读者运行一下这些代码的话,就会发现,工厂方法会创建出远多于1个的产品实例,在笔者运行这段代码时,系统整整产生了9个产品实例。

  因此Factory1作为循环使用产品实例的工厂在多线程环境中是失败的。使用类似于代码清单4的客户端进行试验的话,可以看出系统自始至终仅仅创建了一个产品实例。






  • 上一篇文章:
  • 下一篇文章:
  • 分享此文:该页面添加到 Mister Wong 添加到雅虎Yahoo!收藏 Add to:Del.icio.us Post to Furl Digg this 添加到Google书签 reddit spurl blogmarks 365Key 评论  收藏  分享  打印
     我来说两句
    姓名:       验证码:   
    主页: 
    评分: 1分 2分 3分 4分 5分
    本频道近期热评文章:
      关于我们 | 联系我们 | 站点地图 | 广告投放 | 友情链接 | 在线留言 | 版权申明
    版权所有 © 2004-2007 顶尖设计(bobd.cn)
    未经授权禁止转载,摘编,复制本站内容或建立镜像. 沪ICP备07504942号 
    网络110
    报警服务