为什么List <t>不是线程安全的?</t>

时间:2009-04-01 03:49:57

标签: .net generics thread-safety

来自以下网站:

http://crfdesign.net/programming/top-10-differences-between-java-and-c

  

不幸的是,List<>不是线程安全的(C#的ArrayList和Java   Vector是线程安全的。 C#还有一个Hashtable;通用版本是:

是什么让List<T>不是线程安全的?它是.NET框架工程师的实现问题吗?或者泛型不是线程安全的吗?

6 个答案:

答案 0 :(得分:67)

您确实需要对Java的Vector类型的线程安全性进行分类。 Javas Vector可以安全地从多个线程使用,因为它在方法上使用同步。国家不会被腐败。

但是,Java的向量的有用性受限于多个线程而没有额外的同步。例如,考虑从向量中读取元素的简单行为

Vector vector = getVector();
if ( vector.size() > 0 ) { 
  object first = vector.get(0);
}

此方法不会破坏向量的状态,但也不正确。没有什么能阻止另一个线程在if语句和get()调用之间改变向量。此代码可以并且最终因竞争条件而失败。

这种类型的同步仅在一些场景中有用,而且肯定不便宜。即使您不使用多个线程,也要为同步支付明显的价格。

.Net选择不在默认情况下支付此价格,仅用于有限的用途。相反,它选择实现无锁定列表。作者负责添加任何同步。它更接近C ++的“仅为你使用的东西付费”的模式

我最近写了几篇关于使用仅具有内部同步的集合(例如Java的vector)的危险的文章。

参考矢量线程安全:http://www.ibm.com/developerworks/java/library/j-jtp09263.html

答案 1 :(得分:20)

为什么 它是线程安全的?不是每个班级都是。实际上,默认情况下,类是线程安全的。

线程安全意味着修改列表的任何操作都需要与同时访问互锁。即使对于那些只能由单个线程使用的列表,这也是必要的。这将是非常低效的。

答案 2 :(得分:9)

实现非线程安全类型只是一个设计决策。集合在某些集合上提供接口SyncRoot的属性ICollectionSynchronized()方法,以显式同步数据类型。

使用SyncRoot锁定多线程环境中的对象。

lock (collection.SyncRoot)
{
   DoSomething(collection);
}

使用collection.Synchronized()获取集合的线程安全包装。

答案 3 :(得分:2)

对于真正的线程安全性,List<>和其他集合类型需要是不可变的。随着.NET 4.0的并行扩展在.NET 4.0中出现,我们将看到最常用集合的线程安全版本。 Jon Skeet触及了其中的一部分。

答案 4 :(得分:2)

JaredPar提到的竞争条件可能性是依赖Vector假设的线程安全性的可怕后果。这种情况导致“每第九个星期二应用程序都会做一些奇怪的事情” - 很多缺陷报告会让你感到疯狂。

有许多真正的线程安全集合coming in .Net 4,有一个有趣的副作用,它们允许单线程modification of the collection while enumerating,但是有一个performance hit附带线程 - 安全,有时是一个相当大的安全。

因此,框架开发人员要做的合乎逻辑的事情是让95%的用户尽可能保持高性能,这些用户可能不会进行线程化并依赖那些做多线程的用户来了解他们拥有什么为了保证安全。

答案 5 :(得分:0)

使用SynchronizedCollection它还提供了一个Constructor-Parameter来使用共享同步:)