C# 实例属性的Volatile关键字和锁定

C# 实例属性的Volatile关键字和锁定,c#,C#,我有一些控制器类实例属性的代码,如下所示: public class Controller { private static volatile Controller _instance; private static object syncRoot = new Object(); private Controller() { } public static Controller Instance { get {

我有一些控制器类实例属性的代码,如下所示:

public class Controller
{
    private static volatile Controller _instance;
    private static object syncRoot = new Object();

    private Controller() { }

    public static Controller Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (syncRoot)
                {
                    if (_instance == null)
                        _instance = new Controller();
                }
            }

            return _instance;
        }
    }

    public void Start()
    {

    }
}
get
{            
    lock (syncRoot)
    {
        if (_instance == null)
            _instance = new Controller();
    }            

    return _instance;
}
在阅读之后,我不确定第二个空检查是否冗余,以及编写getter的更好方法是否如下所示:

public class Controller
{
    private static volatile Controller _instance;
    private static object syncRoot = new Object();

    private Controller() { }

    public static Controller Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (syncRoot)
                {
                    if (_instance == null)
                        _instance = new Controller();
                }
            }

            return _instance;
        }
    }

    public void Start()
    {

    }
}
get
{            
    lock (syncRoot)
    {
        if (_instance == null)
            _instance = new Controller();
    }            

    return _instance;
}

这两种实现中哪一种更适合多线程性能和干度(冗余消除)?

实现这一点的经典方法是:在获取锁之前检查一次,以减少开销(获取锁相对昂贵)-然后在获取锁后再次检查,以确保它尚未设置

编辑:正如前面指出的
懒惰
是一个更好的选择,为了完整起见,我将这个答案留在这里

if (_instance == null)
{
    lock (syncRoot)
    {
        if (_instance == null)
            _instance = new Controller();
    }            
}

return _instance;

更好的选择是使用:

private static readonly Lazy\u instance=new Lazy
(()=>新控制器());
专用控制器(){}
公共静态控制器实例
{
得到
{
返回_instance.Value;
}
}
但是,如果您使用的是.NET4之前的版本,我建议您阅读。它讨论了上述技术的优缺点,并为.NET 3.5及更早版本提供了一个更好的惰性实例化单例实现。

这被称为“双重检查锁定”模式。这是一种低锁优化尝试,因此非常危险

该模式不能保证在CLR v1.0上正常工作。在以后的版本中是否有这样的保证是一个有争议的问题;有些文章说可以,有些文章说不可以。这很令人困惑

我会完全避免使用它,除非您有很好的理由认为使用锁定的解决方案不足以满足您的需要。我会使用更高级的原语,比如由Joe Duffy等专家编写的
Lazy
。他们更有可能是正确的

这个问题是重复的

有关更多信息,请参见此处的详细答案。特别是,如果您打算编写任何低锁代码,您必须阅读Vance的文章:

乔的文章:


注意,Vance的文章声称双重检查锁定保证在CLR v2中工作。我不清楚本文中讨论的保证是否在CLR v2中实际实现;我从来没有从任何人那里得到过一个直接的答案,也听说他们都没有按照规定实施。再一次,当你自己做这个低锁的东西时,你是在没有网的空中飞人;如果可能,请避免使用。

在锁定对象之前要进行检查,以避免发生不必要的锁定 您还希望在锁定后进行检查,以避免对象的多次实例化


第一个是不需要的,但出于性能考虑非常可取

不需要,您希望在锁定前进行检查