C# ConcurrentDictionary构造函数是线程安全的吗?

C# ConcurrentDictionary构造函数是线程安全的吗?,c#,C#,例如,如果我有如下代码: if (dictionary == null) { dictionary = new ConcurrentDictionary(); } 多个线程是否可以读取它的null值并同时创建新的ConcurrentDictionary 我说的是System.Collections.Concurrent提供的ConcurrentDictionary 实例化后,它是线程安全的(即多个线程可以添加/访问/从中访问而不会出现问题)。在您的情况下,您需要使语句实例化为线程安全的

例如,如果我有如下代码:

if (dictionary == null) {
    dictionary = new ConcurrentDictionary();
}
多个线程是否可以读取它的null值并同时创建新的ConcurrentDictionary

我说的是System.Collections.Concurrent提供的ConcurrentDictionary

实例化后,它是线程安全的(即多个线程可以添加/访问/从中访问而不会出现问题)。在您的情况下,您需要使语句实例化为线程安全的,您可以使用关键字:

实例化后,它是线程安全的(即多个线程可以添加/访问/从中访问而不会出现问题)。在您的情况下,您需要使语句实例化为线程安全的,您可以使用关键字:


ConcurrentDictionary
是线程安全的。但您显示的代码与
ConcurrentDictionary
的内部结构无关。一切外部的
ConcurrentDictionary
都由您负责。因此,您应该确保只进行一次初始化

一种方法是使用


ConcurrentDictionary
是线程安全的。但您显示的代码与
ConcurrentDictionary
的内部结构无关。一切外部的
ConcurrentDictionary
都由您负责。因此,您应该确保只进行一次初始化

一种方法是使用


大多数构造函数都是线程安全的,因为它们只发生在一个线程上。如果它们访问静态字段或调用非线程安全的委托或其他东西,则会出现异常,但这种情况很少见(通常是个坏主意)

这不是你问题的关键,因为在你的例子中,不是构造器,而是赋值

如果另一个线程可以访问
字典
,那么确实存在竞争,一个线程可以分配给
字典
,只是被另一个线程覆盖(并且可能有一段时间,两个线程将
字典
视为具有不同的值)


这可能是个问题。它可能仅仅是次优的(例如,并发字典被用作缓存,一些缓存值丢失,必须重新计算,但仍能正常工作),或者可能是灾难性的。如果多个线程可以看到
字典
,则应锁定并重新测试,使用
联锁。CompareExchange
惰性
大多数构造函数都是线程安全的,因为它们只发生在一个线程上。如果它们访问静态字段或调用非线程安全的委托或其他东西,则会出现异常,但这种情况很少见(通常是个坏主意)

这不是你问题的关键,因为在你的例子中,不是构造器,而是赋值

如果另一个线程可以访问
字典
,那么确实存在竞争,一个线程可以分配给
字典
,只是被另一个线程覆盖(并且可能有一段时间,两个线程将
字典
视为具有不同的值)


这可能是个问题。它可能仅仅是次优的(例如,并发字典被用作缓存,一些缓存值丢失,必须重新计算,但仍能正常工作),或者可能是灾难性的。如果多个线程可以看到
字典
,则应锁定并重新测试,使用
联锁。CompareExchange
Lazy

该代码示例不是线程安全的,因为它允许多个线程查看“字典”在新运算符更改以分配新实例之前,变量为null

使用lock对象和lock语句是有效的,但是每次使用字典时都会添加一个lock变量并导致锁惩罚

以下版本不需要锁变量,并且不会在每次使用dictionary字段时产生锁惩罚

if( dictionary == null )
    Interlocked.CompareExchange( ref dictionary, new ConcurrentDictionary(), null );

dictionary.xxx()
  • 请记住,ConcurrentDictionary是一个泛型类型,因此上面的新运算符需要包含类型参数

该代码示例不是线程安全的,因为它允许多个线程在新操作符更改分配新实例之前,在null时查看“dictionary”变量

使用lock对象和lock语句是有效的,但是每次使用字典时都会添加一个lock变量并导致锁惩罚

以下版本不需要锁变量,并且不会在每次使用dictionary字段时产生锁惩罚

if( dictionary == null )
    Interlocked.CompareExchange( ref dictionary, new ConcurrentDictionary(), null );

dictionary.xxx()
  • 请记住,ConcurrentDictionary是一个泛型类型,因此上面的新运算符需要包含类型参数

简言之,是的。ConcurrentDictionary将确保其访问项目、设置项目等是线程安全的。对于将另一个变量分配给同一个变量,它无能为力。你也需要用一些线程安全性来包装初始化。实际上你的问题没有意义。构造函数总是返回一个新的对象,所以如果你的代码可能会运行多个线程,那么构造函数是线程安全的并不重要,但是它周围的代码是安全的。简言之,是的。ConcurrentDictionary将确保其访问项目、设置项目等是线程安全的。对于将另一个变量分配给同一个变量,它无能为力。你也需要用一些线程安全性来包装初始化。实际上你的问题没有意义。构造函数总是返回一个新对象,因此,如果您的代码可能要与多个线程一起运行,那么构造函数是线程安全的并不重要,但与其周围的代码是相关的。最好说:ConcurrentDictionary的对象在创建后是线程安全的。但是在您的代码中,您正在询问对ob的引用的线程安全性
var dic = _dictionary.Value; // extract instance.
if( dictionary == null )
    Interlocked.CompareExchange( ref dictionary, new ConcurrentDictionary(), null );

dictionary.xxx()