C# 中的单例线程安全 - 为什么要添加双重检查
本文关键字:添加 检查 为什么 单例 线程 安全 | 更新日期: 2023-09-27 18:33:45
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;
}
}
}
我不明白为什么要仔细检查!我读到这个双重检查是为了解决线程并发问题 - 但是......
锁会解决它 - 那么为什么我们需要首先"如果"
如果这个单例没有第一个"如果",它仍然是线程安全的 - 对吧?
如果第一个"if"为假 - 所以 thread1 将初始化"实例"对象 => 现在,"实例"不为空,线程 1 仍在锁定块中 ===>> 现在,线程 2 检查第一个"如果"并将得到 false => 所以他不会到达"锁"并立即返回实例,线程 2 能够更改"实例"的属性 => 所以线程 1 &&线程 2 在同一个"实例"对象上"工作"=> 所以线程安全吗...或者我在这里错过了什么。
1.锁会解决它 - 那么为什么我们需要首先"如果"
因此,除非需要创建单例的新实例,否则不会锁定 thred。
lock
是一项非常昂贵的操作,因此值得进行额外的检查。
2.如果这个单例没有第一个"如果",它仍然是线程安全的 - 对吧?
是的,但速度明显慢。
3.线程 1 &&线程 2 在同一个"实例"对象 => 上"工作",所以线程在哪里安全
这就是单例的全部意义,所有线程只有一个实例。这是线程安全的事情...
我假设如果线程 A 在lock
之前被打断;ThreadB 成功完成了单一实例的创建,然后当 ThreadA 恢复时,它将在释放锁后尝试重新创建单一实例。
if 检查单例是否已实例化,如果没有,则会创建一个新的 instace。 和锁确保线程安全。
如果没有 if,它会在每次调用时创建一个新的 instace(不是单例的想法)。 如果没有锁,两个线程可以模拟创建一个实例,因此可能存在两个实例。
如果您只使用单线程,则可以擦除锁。 否则(在MT上)强烈建议使用它。
这是马里兰大学的一篇很好的论文,关于为什么推荐它(以及为什么它并不总是在现代优化编译器中工作) 如果你有时间,这是一个很好的阅读。
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html