你的单例足够单吗

什么是单例:
单例模式( Singleton )是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。实现单例模式的思路是:一个类能返回对象一个引用 ( 永远是同一个 ) 和一个获得该实例的方法(必须是静态方法,通常使用 getInstance 这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。 [ wikipedia]
Delphi 源码中的单例应用:
var
  FClipboard: TClipboard;

function  Clipboard: TClipboard;
begin
  
if  FClipboard =  nil  then
    FClipboard := TClipboard.Create;
  Result := FClipboard;
end ;



问题的提出:
上述代码不是线程安全的。假设 A 率先调用函数 Clipboard,局部变量 FClipboard会先进行实例化。在实例尚未完全创建完之前,如果 B 也尝试调用函数Clipboard,那么它也会去对 FClipboard 进行实例化。因为变量FClipboard此时依然为空指针。于是乎AB分别创建了一个 TClipboard 的实例,单例不再单!其中的一个并且变成了一个内存泄漏。这种泄漏往往发送在构建函数需要耗费较长时间的情况下。如何将上述代码改成线程安全的呢?其实可以通过加入临界区处理来解决

var
 
FClipboard: TClipboard;
  GClipboardLocker: TRTLCriticalSection;

function Clipboard: TClipboard;
begin
  if FClipboard = nil then
  begin

   EnterCriticalSection(GClipboardLocker);
   
try
     
if FClipboard = nil then
       FClipboard := TClipboard.Create;
   
finally
     LeaveCriticalSection(GClipboardLocker);
   
end;
 end
;
  Result := FClipboard ;
end;

initialization
  InitializeCriticalSection(GClipboardLocker);
finalization
  DeleteCriticalSection(GClipboardLocker);
end. 

 

小结:
单例模式简约而不简单,当开发往多线程延伸之后,可能还会爆出更多的问题。单例就是一个全局变量,建议不要滥用,否则软件的层次结构会被破坏。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值