我发现 Java Concurrency in Practice 这本书是为 Java 编写多线程代码的优秀指南。我想知道书中描述的一般原则在多大程度上适用于 .Net。我对编写自己的无锁代码不感兴趣——我只想使用可靠、易于理解的技术并利用现有的同步和并发 API。就此而言,对我来说,这本书的主要收获是:
- 锁定——在一个线程的锁内所做的状态更改对于同一对象的锁内的所有其他线程都是可见的。毫无疑问,这在 .NET 中有效,足以编写线程安全程序,但如果我们不能依赖以下机制,它会导致不必要的锁定。
- 安全发布——有效不可变对象(immutable对象)(发布后未更改的对象)的最新状态对所有线程可见,前提是满足以下条件之一。请注意,查看对象引用的最新状态不一定与查看对象本身的最新状态相同——在 Java 中,安全发布是有效的,因为之前发生的关系具有传递性。
- 通过所有线程中的锁同步访问它的引用
- 它是通过一个可变变量引用的
- 它是从同步或并发集合中发布的。
- 只有 final 字段(在 .NET 中为只读)的正确构造的不可变对象(immutable对象)的最新状态是线程安全的,无论它们是如何发布的。
我希望所有这些都能正常工作,否则会给生活带来不必要的困难,但从我已经准备好的情况来看,.Net 的模型(至少按照指定的那样)非常薄弱。有没有人尝试为 .NET 构建一个 happens-before 模型?我认为这是一个急需在 .Net 中解决的领域。据我所知,没有一本可以提供相同“舒适度”的 .Net 等效书籍——似乎至少部分问题是缺乏明确定义的 .NET 内存模型。
最佳答案
一般概念是相同的。不过,需要考虑 Java 和 .NET 内存模型之间的差异。这通常涉及使用 Interlocked函数(在 Java 中),VolatileRead/VolatileWrite或 explicit memory barrier .
为 .NET 指定了两种内存模型。 .NET Framework ECMA 标准的第 12 部分第 I 部分中指定的弱内存模型。 Stronger memory model实际上是由 .NET Framework 运行时实现的。 Joe Duffy 描述了另一种定义. IKVM.NET blog 中描述了 .NET 内存模型与 Java 内存模型不同的一个实际案例。 .
关于您的观点:
锁定的工作方式与 Java 中的相同。
安全发布 - 前两个场景(锁和 volatile)的工作方式与 Java 对应场景相同。
.NET 中的同步集合已被弃用,但它们在内部使用锁,因此它们的工作方式与访问被锁定时完全相同。
Concurrent collections作为 .NET 3.5 的一部分添加,内部使用无锁技术,因此它们应该在不同线程之间保持内存一致。不过,我不确定它们是否与内存一致。
- 根据定义,不可变对象(immutable对象)是线程安全的。一旦你构建了一个不可变对象(immutable对象),它就不能再被修改。创建它的线程是唯一可以在缓存中拥有其副本的线程。一旦您发布它,所有其他线程将获得一个最新的副本,并且该副本保证不会更改。因此,唯一的痛点是出版本身。您仍然需要注意安全发布,以免创建不可变对象(immutable对象)的两个实例,但是当从任何线程访问时,这些实例中的每一个都是线程安全的。
关于java - 安全发布和初始化安全在 .NET 中是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8707215/