以下内容来自以下网站:
http://crfdesign.net/programming/top-10-differences-between-java-and-c
不幸的是,
List<>
不是线程安全的(C# 的ArrayList
和 Java 的Vector
是线程安全的)。 C# 还有一个Hashtable
;它的泛型版本是:
是什么让 List<T>
不是线程安全的?这是 .NET 框架工程师实现上的问题吗?还是说泛型本身就不是线程安全的?
以下内容来自以下网站:
http://crfdesign.net/programming/top-10-differences-between-java-and-c
不幸的是,
List<>
不是线程安全的(C# 的ArrayList
和 Java 的Vector
是线程安全的)。 C# 还有一个Hashtable
;它的泛型版本是:
是什么让 List<T>
不是线程安全的?这是 .NET 框架工程师实现上的问题吗?还是说泛型本身就不是线程安全的?
您需要对Java的Vector类型的线程安全性进行分类。 Java的Vector可以安全地从多个线程中使用,因为它在方法上使用同步。 状态不会被破坏。
但是,在没有额外同步的情况下,Java的向量在多个线程中的实用性是有限的。 例如,考虑从向量中读取元素的简单操作。
Vector vector = getVector();
if ( vector.size() > 0 ) {
object first = vector.get(0);
}
这种方法不会破坏向量的状态,但它也是不正确的。没有任何东西阻止另一个线程在 if 语句和 get() 调用之间对向量进行变异。由于竞争条件,这段代码可以并且最终将失败。
这种类型的同步仅在少数情况下有用,并且显然不便宜。即使您不使用多个线程,也会付出明显的同步代价。
.Net选择默认情况下不为仅有限用途的场景支付此价格。相反,它选择实现了一个无锁的列表。作者需要添加任何同步。 它更接近于C++的“按使用付费”的模式。
我最近写了几篇关于仅具有内部同步(如Java的向量)的集合的危险的文章。
参考向量线程安全性:http://www.ibm.com/developerworks/java/library/j-jtp09263.html
Count()
是否包含足够完成所需操作的值,那么如果没有要处理的内容,就可以避免锁定获取/释放周期。 如果集合通常不包含足够的数据以值得处理,则这种优化有时可以提供显着的好处。 偶尔会检查Count()
,决定获取锁定,再次检查Count()
,并发现数据已经消失,因此不再需要执行任何操作,但是... - supercatCount
这样的调用可以用作廉价的锁避免技巧。但请注意,这在vector
中实际上并不起作用,因为size
本身会获取锁。 - JaredPar为什么会是线程安全?并不是每个类都是线程安全的。事实上,默认情况下,大多数类都不是线程安全的。
线程安全意味着修改列表的任何操作都需要与同时访问进行交互锁定。即使只有一个线程将使用这些列表,这也是必要的。这样做将非常低效。
将类型实现为非线程安全的是一种设计决策。集合提供接口ICollection
的属性SyncRoot
以及某些集合的Synchronized()
方法,用于显式同步数据类型。
在多线程环境中使用SyncRoot
来锁定对象。
lock (collection.SyncRoot)
{
DoSomething(collection);
}
collection.Synchronized()
获取集合的线程安全包装器。为了实现真正的线程安全,List<>
和其他集合类型需要是不可变的。随着 .NET 4.0 的并行扩展的推出,我们将看到最常用的集合的线程安全版本。
Jon Skeet 提及了其中的一些内容。
使用SynchronizedCollection,它还提供了一个构造函数参数来使用共享同步 :)
ArrayList
提供了Synchronized包装器。 - Mark Hurd