这个问题似乎有些奇怪,但与可能的可见性问题有关。问题的灵感来自Java编程语言(> jdk5)中的一个案例,请考虑:
public class InmutableValue {
private int value;
public InmutableValue(int value) {this.value = value;}
public int getValue() {return value;}
}
尽管有相反的信念,但上述课程并非线程安全。在多线程环境中,不保证其他线程可以看到“值”。为了使其成为线程安全的,我们需要强制实施“先发生”规则。这可以通过标记“最终”字段来实现。
这个案例让我想知道.Net运行时是否也是如此。举个例子来说:
public class InmutableValue {
private int value;
public InmutableValue(int value) {this.value = value;}
public int Value { get{return value;}}
}
据我所知,将值字段标记为'readonly'并不能提供与'final'对java相同的保证(但我可能非常错误,希望如此)。那么我们是否需要将字段标记为“易变”(或使用内存屏障等)以确保其他线程的可见性?或者是否有其他规则可以确保可见性?
答案 0 :(得分:2)
你可能会担心内存模型较弱的cpu内核,比如Alpha和Titanium。它有一个内存写缓冲区,可以重新排序内存写入,使得可以在值字段值之前写入对象引用。也许灵感来自Raymond Chen的博客?
你错过了一个重要的细节。要创建线程竞争,必须有两个都使用对象引用的线程。一个创建对象并存储引用,另一个使用该引用。 基本上是线程不安全的,需要同步对共享对象引用的访问。同步代码(如 lock 语句)也可确保刷新回写缓冲区。这可以防止读取属性的线程看到过时的值。
答案 1 :(得分:1)
无论如何,readonly
关键字只能确保在构造函数中分配字段,而不是在其他任何地方(在类内)。
就构造函数为thread-safe in general meaning而言,一旦创建对象将返回相同的值:
static ImmutableValue imv = new ImmutableValue(123);
// thread 1, object is not created
imv.Value; // NullReferenceException, as usually
// thread 2, object is created
imv.Value; //123
// thread 3, object is created
imv.Value; //123
要编辑private
字段,您需要使用Reflection,是的,您需要在此类代码执行期间锁定对象,以保证冻结此时尝试读取值的所有线程。