这个示例线程是否安全?

假设我有一个充当数据缓存的单例类。 多个线程将从缓存中读取,并且单个线程将定期刷新它。 它看起来像这样:

public sealed class DataStore { public static DataStore Instance { get { return _instance; } } public Dictionary FooBar { get; private set; } static DataStore() { } private DataStore() { } public void Refresh() { FooBar = GetFooBarFromDB(); } private static readonly DataStore _instance = new DataStore(); } 

我的问题基本上是,当其他线程可能正在访问FooBar时, Refresh()是否安全? 我需要使用锁,还是我的获取和设置操作是primefaces的? 我是否需要显式声明volatile字段来备份我的属性?

PS,如果有人能想到这个问题的更具描述性的标题,我很乐意欢迎它。

编辑:修复了我的例子来纠正非primefaces代码。

是的,在这种情况下你需要显式同步,因为另一个线程可以获得FooBar并在你完成写入之前开始阅读它。

但是,如果你这样做,

 public void Refresh() { var tmp = new Dictionary(); // Fill out FooBar from DB FooBar = tmp; } 

那么你就不需要添加显式同步,因为从一个引用到另一个引用的切换是primefaces的。

当然,这里有一个隐含的假设,即在Refresh方法之外没有写入。

编辑:您还应该从自动实现的属性切换到手动实现的属性,并使用volatile修饰符声明支持变量。

您的示例不是线程安全的。 Dictionary不是一个线程安全的类,任何线程都可以在执行Refresh时读取。 您可以放置lock或使用其中一个类似ConcurrentDictionary的线程安全类。

因为您公开公开字典,所以您遇到的更多问题是您编写的代码,这些代码可以访问字典本身的方法。 正如@Icarus指出你应该使用ConcurrentDictionary但我认为任何forms的实例锁定都无法帮助你。

您可以轻松地将一个线程添加到集合中,而另一个线程则迭代它。

编辑我在说什么..从不暴露静态字典或任何其他集合类型。 始终使用并发版本

好吧,我们同意您当前的代码不是线程安全的。 因此,您必须使用同步function,因为FooBar是您的关键部分

如果你让它public ,你期望 DataStore类之外的人会相应地采取行动。 然而,这是一个糟糕的设计决定。

所以,我建议你把所有东西都包装到你当前的类中,用这样的东西: 实现线程安全的字典的最佳方法是什么?