我的应用程序中有一个缓存的用户列表。几个管理页面需要所有用户的列表(总数足够小,这不是问题)。
我采取的方法是:
好主意。但我刚刚编写了一些执行此操作的单元测试,但它不起作用。因为有 2 个线程正在重建列表,而第二个写入列表的线程获胜。我可以在列表的重建周围加上
lock (this)
,效果很好。
但这是一个糟糕的方法。非常适合识别问题,但不适合生产。
在正常使用中,这种返回任何列表都是不可变的方法非常有效。如果没有
lock
我怎样才能完成这个任务?
在 C# 中,这是一个与语言无关的问题,尽管可能存在一些 C# 类等,这使得这是一个简单的解决方案。
如果没有
我怎样才能完成这个任务?lock
你不能。至少如果您想坚持使用包含可变
List<T>
对象的 User
,至少不需要。 List<T>
集合不是线程安全的。即使是这样,在不同步的情况下改变它包含的 User
元素也会导致错误/未定义的行为。
我可以在列表的重建周围加上
,效果很好。但这是一个糟糕的方法。lock (this)
lock
语句,这意味着您仅保护与共享状态(列表和用户)的交互,而不是在共享之前重建新列表,则 contention 是可能很小,而且性能相当不错。
当然还有其他可用的选项,不涉及共享
List<T>
,例如:
ConcurrentDictionary<K,V>
已更新为GetOrAdd
/AddOrUpdate
。ImmutableList<T>
已更新为ImmutableInterlocked.Update
。这两种低锁替代方案都要求
User
类型应该是不可变的。它们不仅会表现得更好(很可能),而且也会更方便。