我有一个类,它有两个属性和两个方法。比如下面这个。(请忽略数据类型或返回类型,这只是一个典型的场景)
// 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)作为一种技术来确保它的线程安全,但考虑到以下几点,什么是使它线程安全的最佳技术:
只有两个属性被读取/更新。因此,不确定方法内部的锁定是否是一种好的技术。
如果我只是让属性而不是方法或类成为线程安全的,这就足够了吗?
此外,有没有一种方法可以使整个类的线程安全,而不是单个方法或属性?.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。