我很少使用单身人士,在这种情况下,这是合适的。在尝试调查其最佳实现时,我遇到了一些代码,这让我相信我不正确地理解括号如何封装“范围”。
public sealed class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
Singleton()
{
}
public static Singleton Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
}
我很困惑当我尝试访问“实例”时会发生什么。假设我正在处理日志单例(我对单例的有用应用程序),它有一个方法“WriteLine(string line)”
我打电话的时候:
Singleton.Instance.WriteLine("Hello!");
它在执行“WriteLine?”
的整个方法时保持锁定如果我将实例分配给外部变量,例如:
,该怎么办?Singleton Console = Singleton.Instance;
现在对单身人士之外的单身人士有一个恒定的引用。 Console.WriteLine("Hello!")
也像Singleton.Instance.WriteLine("Hello!")
一样完全线程安全吗?
无论如何,我只是混淆了如何使单例线程安全,以及在显式访问属性时它是否只是线程安全。我以为Singlton.Instance.WriteLine("...")
会首先提取实例,从而保留锁的范围,然后在返回的实例上执行WriteLine
,因此在锁被释放后执行写操作。
任何有助于消除我对如何理解这些功能的误解的帮助。
答案 0 :(得分:6)
在执行
Singleton.Instance.WriteLine("Hello!");
的整个方法时,WriteLine
是否会保持锁定?
不,锁只保护你的单身人士的创造。 WriteLine
执行解锁(当然,除非它在内部获得自己的锁)。
Console.WriteLine("Hello!")
是否也完全是线程安全的,如Singleton.Instance.WriteLine("Hello!")
?
与Singleton.Instance
一样安全或不安全,因为锁定不会在Instance
的吸气之外维持。
无论如何,我只是混淆了如何使单例线程安全
Lock使获取单例线程安全实例的过程成为可能。使单例线程安全的方法是一个不依赖于您的对象是否是单例的过程。没有简单的交钥匙一刀切的解决方案,使线程不安全的对象以线程安全的方式运行。你可以一次解决一个方法。
答案 1 :(得分:4)
不,锁定在return
上结束,您对Instance
执行的任何操作都是"外部"锁。
lock
在这一点上的优势只有一个:
Singleton
实例。请注意,通常情况下,最好使用Lazy<>
类。要获得相同的结果,您必须使用它:
public static Lazy<Singleton> Instance = new Lazy<Singleton>();
(Lazy<T>
可以使用三个modes,默认值ExecutionAndPublication
,相当于该代码)
答案 2 :(得分:3)
任何有助于消除我对如何理解这些功能的误解的帮助。
在Head First Design Patterns中,有一个使用&#34;代码磁铁&#34;的线程安全单例的一个很好的例子。您可以考虑两个线程可以执行相同代码的所有可能方式。它完成了三个列,一个用于两个线程中的每一个,第三列用于返回的假定单例的值。这是一个练习,您可以垂直放置代码片段以显示两个线程之间的操作顺序。我将尝试使用SO中的有限格式以及您的代码示例来重现它。
代码片段(没有锁定)将是:
get{if (instance == null){instance = new Singleton(); }return instance; }
由于线程的执行方式,你可以找到一个可能导致返回类的两个实例的执行:
Thread One Thread Two Value instanceget{ nullget{ nullif (instance == null){ nullif (instance == null){ nullinstance = new Singleton(); } Object_1return instance; } Object_1instance = new Singleton(); } Object_2return instance; } Object_2
在lock
之后的get {
,Thread Two
将无法继续(如上所述),直到Thread One
执行return instance;
并释放锁:
Thread One Thread Two Value instanceget{ [takes lock] nullget{ [blocks on lock] nullif (instance == null){ nullinstance = new Singleton(); } Object_1return instance; } [releases lock] Object_1[continues] if (instance == null) { Object_1return instance; } Object_1