【问题标题】:Is a read-only HashSet inherently threadsafe?只读 HashSet 本质上是线程安全的吗?
【发布时间】:2014-11-25 15:56:22
【问题描述】:

如果我在Lazy 初始化程序中初始化HashSet<>,然后从不更改内容,那么HashSet<> 本身是线程安全的吗?是否存在需要锁定的读取操作?

关于集合的类似 Java 问题 here,基本上说是,但有一些警告(不适用于这种情况)。

【问题讨论】:

  • 是的,如果它真的没有改变并且在构造时没有被访问,那么是的,你会没事的。也就是说,没有什么可以阻止某人更改它,因此它的“只读”行为是非强制的。试试不可变集合。
  • @AdamHouldsworth 不幸的是,不可变集合具有可怕的性能ayende.com/blog/164739/immutable-collections-performance
  • @ChrisMarisic 性能不佳是众所周知的。也就是说,对于许多场景,性能问题不会浮出水面。您始终可以通过在内部包装非不可变集合来实现自己的集合,这些年来对它们进行了许多优化。
  • @AdamHouldsworth 如何将缓慢的包裹起来让它变得更快?更不用说保持不变性了?在 C# 中保持不变是荒谬的。然而,他们在 Ayende 的 cmets 中讨论的代码提供了有趣的构造,让您自己动手。
  • @ChrisMarisic 我的意思是包装一个数组或字典之类的东西以便滚动你自己的,具有一个一旦构建就不允许更改的 API。我不是指包装现有的不可变类型。

标签: c# .net multithreading thread-safety


【解决方案1】:

是的,是的。只要HashSet 对象的构造是线程安全的,只要内容不变,访问它就始终是线程安全的。

如果你initializeLazy使用LazyThreadSafetyMode.PublicationOnly你可以确定Lazy的初始化是线程安全的。

当多个线程尝试同时初始化一个Lazy<T>实例时,允许所有线程运行初始化方法(或默认构造函数,如果没有初始化方法)。第一个完成初始化的线程设置Lazy<T> 实例的值。该值将返回给同时运行初始化方法的任何其他线程,除非初始化方法在这些线程上引发异常。

一个小代码示例:

var l = new Lazy<HashSet<string>>( () => new HashSet<string>() { "a" }
                                 , LazyThreadSafetyMode.PublicationOnly
                                 );

【讨论】:

  • 虽然我相信在实践中确实如此,但我无法保证非修改 HashSet 操作是线程安全的。事实上,HashSet 文档另有说明:msdn.microsoft.com/en-us/library/bb359438(v=vs.110).aspx“不保证任何实例成员都是线程安全的。”您是否有证据表明在这种情况下线程安全得到保证?
猜你喜欢
  • 2011-07-19
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-12
  • 1970-01-01
相关资源
最近更新 更多