1

我想知道在属性中正确使用锁。我正在编写一个多线程服务器应用程序,其中吞吐量非常重要。如果我有这样声明的属性:

    private DataPoint a;
    private object aLock = new object();

最保守的锁似乎如下(称之为方法1)。但是,在这种情况下,在初始调用之后的每次调用中,都会产生锁开销:

    public DataPoint A
    {
        get
        {
            lock (aLock)
            {
                if (a == null)
                {
                    a = new DataPoint();
                }

                return a;
            }
        }
    }

或者,我应该将锁移动到设置“a”的行(称为方法 2)。在这种情况下,“a”可能会被设置多次(这没关系),但是一旦设置,就没有锁的开销。

    public DataPoint A
    {
        get
        {
            if (a == null)
            {
                lock(aLock)
                {
                    a = new DataPoint();
                }
            }

            return a;
        }
    }

锁定对属性的并发访问的推荐方法是什么?是方法1,方法2还是以上都不是?

谢谢。

4

3 回答 3

7

在 .NET 4 中,您拥有System.Lazy<T>为您处理这些问题的类型:

class MyClass
{
    private readonly Lazy<DataPoint> lazy =
        new Lazy<Singleton>(() => new DataPoint());

    public DataPoint Instance { get { return lazy.Value; } }
} 

乔恩斯基特提供

于 2012-09-24T22:14:07.103 回答
2

在您的锁定示例中,您这样做是为了初始化一个值。假设 null 条件意味着需要初始化该值,您应该在获取锁之前和之后检查它:

if(a == null)
{
  lock(aLock)
  {
    if(a == null)
      a = new DataPoint();
  }
}

这样做的原因是,当一个线程正在等待锁时,一旦它获得锁,它所要做的工作就有可能已经由另一个线程完成了。所以当线程获得锁时,它应该检查是否还需要完成工作。

于 2012-09-24T22:06:57.333 回答
1

您应该在锁定之前检查 null 。如果为空,则锁定,并再次检查是否为空。如果它仍然为空,请启动您的 DataPoint 并首先将其分配给一个临时变量。完成后,将其分配给您的成员并返回。

private DataPoint _dataPoint;

public DataPoint A
{
    get
    {
        if(_dataPoint != null)
            return _dataPoint;

        lock (aLock)
        {
            if (_dataPoint == null)
            {
                var dataPoint = new DataPoint();
                // do more stuff with dataPoint
                _dataPoint = dataPoint;
            }

            return _dataPoint;
        }
    }
}
于 2012-09-24T22:07:38.943 回答