Way*_*pps 74 c# singleton design-patterns
我对这里记录的单例模式有一些疑问:http: //msdn.microsoft.com/en-us/library/ff650316.aspx
以下代码是文章的摘录:
using System;
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
Run Code Online (Sandbox Code Playgroud)
具体来说,在上面的例子中,是否需要在锁之前和之后将实例与null进行两次比较?这有必要吗?为什么不先执行锁定并进行比较?
简化以下是否有问题?
public static Singleton Instance
{
get
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
return instance;
}
}
Run Code Online (Sandbox Code Playgroud)
表演锁是否昂贵?
Jon*_*Jon 121
与简单的指针检查相比,执行锁定非常昂贵instance != null.
您在此处看到的模式称为双重检查锁定.其目的是避免昂贵的锁定操作,这只需要一次(当首次访问单例时).实现是这样的,因为它还必须确保在初始化单例时不会出现线程争用条件导致的错误.
可以这样想:只有当答案为"是,对象已经构建"时,才能保证只有裸null检查(没有a lock)才能给出正确的可用答案.但如果答案是"尚未构建",那么你没有足够的信息,因为你真正想知道的是"它还没有构建,没有其他线程打算很快构建它 ".因此,您使用外部检查作为一个非常快速的初始测试,并且只有在答案为"否"时才启动正确的,无错误但"昂贵"的程序(锁定然后检查).
对于大多数情况,上面的实现已经足够了,但是在这一点上,最好去阅读Jon Skeet关于C#中单例的文章,该文章还评估了其他替代方案.
小智 28
懒惰的版本:
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy
= new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance
=> lazy.Value;
private Singleton() { }
}
Run Code Online (Sandbox Code Playgroud)
需要.NET 4和C#6.0(VS2015)或更高版本.
Jon*_*nna 13
执行锁定:相当便宜(仍然比空测试更昂贵).
当另一个线程拥有它时执行锁定:你得到锁定时他们仍然要做的任何事情的成本,增加到你自己的时间.
当另一个线程拥有它时执行锁定,还有许多其他线程也在等待它:致残.
出于性能原因,您总是希望在最短的时间内拥有另一个线程所需的锁.
当然,对于"宽"锁而不是狭义的推理更容易,因此值得从它们开始并根据需要进行优化,但在某些情况下我们从经验和熟悉中学习,其中较窄的适合模式.
(顺便说一下,如果你可能只是使用private static volatile Singleton instance = new Singleton()或者你可能只是不使用单例而是使用静态类,那么两者在这些问题上都会更好).
杰弗里·里克特 (Jeffrey Richter) 建议如下:
public sealed class Singleton
{
private static readonly Object s_lock = new Object();
private static Singleton instance = null;
private Singleton()
{
}
public static Singleton Instance
{
get
{
if(instance != null) return instance;
Monitor.Enter(s_lock);
Singleton temp = new Singleton();
Interlocked.Exchange(ref instance, temp);
Monitor.Exit(s_lock);
return instance;
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
105555 次 |
| 最近记录: |