确保类是线程安全的,只有属性(是否有专门用于此的.NET 4.0技术?)



我有一个类,它有两个属性和两个方法。比如下面这个。(请忽略数据类型或返回类型,这只是一个典型的场景)

// The methods could be invoked by multiple threads
public class Stock
{ 
private static int FaceValue {get; set;}
private static int Percent (get; set;}
//    method that updates the two properties
Public void UpdateStock()
{
FaceValue += 1;
Percent = FaceValue * 100;
}
//   method that reads the two properties
public int[] GetStockQuote()
{
return new int[] { FaceValue, Percent};
}
}

我需要确保这个类是线程安全的。我可以在这两种方法中使用锁(obj)作为一种技术来确保它的线程安全,但考虑到以下几点,什么是使它线程安全的最佳技术:

  1. 只有两个属性被读取/更新。因此,不确定方法内部的锁定是否是一种好的技术。

  2. 如果我只是让属性而不是方法或类成为线程安全的,这就足够了吗?

  3. 此外,有没有一种方法可以使整个类的线程安全,而不是单个方法或属性?.Net 4.0中有推荐的锁定技术吗?

我只是想知道我是在思考这个问题,还是考虑到这些,我已经把它复杂化了。非常感谢提前帮我弄清楚这一点。

Mani

通常,lock可能是这里最简单的方法。

一个可能更好的选择是使这个类不可变。如果你这样做,一旦创建了类,就不能更改类中的值,那么在读取值时就不必担心了,因为没有办法修改它们。

在这种情况下,这可以通过使用一个接受这两个值的构造函数来完成,并将UpdateStock更改为更像:

public Stock GetUpdatedStock()
{
// Create a new instance here...
return new Stock(this.FaceValue + DateTime.Now.MilliSecond, this.FaceValue * 100);
}

编辑:

现在您已经将FaceValue和Percent设置为静态,您将需要同步。lock可能是这里最简单的选项。

使用单个值,您可能会使用Interlocked类以原子方式处理更新,但无法对两个值*进行原子更新,这可能是正确实现线程安全所必需的。在这种情况下,通过lock进行同步将解决您的问题。

*注意:如果您将两个值都放在一个类中,并交换整个类实例,则可以通过Interlocked.CompareExchange在没有锁的情况下执行,但这可能会带来更多麻烦。

没有使线程安全的银弹式解决方案,每个场景都需要自己的解决方案。最明显的是使用lock,但在您的示例中,您可以简化并使用Interlocked类,并将其作为原子操作:

public class Stock
{ 
private static int FaceValue {get; set;}
Public void UpdateStock()
{
//only a single property to update now
Interlocked.Increment(FaceValue);
}
//   method that reads the two properties
public int[] GetStockQuote()
{
var currVal = FaceValue;
return new int[] { currVal, currVal * 100 };
}
}

请参阅MSDN上的Interlocked。

最新更新