不可变对象总是线程安全吗?

时间:2009-11-13 10:59:23

标签: c# thread-safety immutability

可以安全地假设使用或传递不可变对象总是线程安全的吗?

4 个答案:

答案 0 :(得分:9)

是。如果一个对象是真正不可变的,没有发生内部突变,那么该对象本身将是线程安全的。

(无论你处理对象并以线程安全方式传递它都是另一回事!)

“内部突变”是什么意思?

许多对象似乎是从外部不可变的 - 例如,没有属性设置器或明显触发突变的其他成员 - 但这并不意味着对象的私有内部不是'能够改变。

这就是为什么记录对象和/或其成员的可变性和线程安全性的重要性。否则,您的对象的消费者无法在不仔细检查内部的情况下发现这一点(这是一个实现细节,并且可能随时更改)。

答案 1 :(得分:2)

这取决于你对线程安全的意思;正如Eric Lippert's blog指出的那样,这个词可能意味着几件事。不可变对象保证无论何时访问给定实例上的属性或方法,结果总是相同的;这是该实例的线程安全性。但是,如果你有一个包含对不可变对象的引用的可变字段,则通过相同字段的多个调用可能不是同一个实例,因此不一致(即“线程安全”)。

我怀疑你想到的“线程安全”的含义,答案是肯定的。但请记住,不可变对象不是金子弹;它们不会让你对线程交互免疫,它们只是在单个实例中提供一致性。

答案 2 :(得分:1)

正确回答问题:否。

您不能假设不可变对象总是线程安全。

但最有可能的是。另见关于卢克斯答案的讨论。

例如:访问方法或属性getter可能会触发初始化,调用者不知道。 (例如,延迟初始化)这个初始化必须明确地实现线程安全。

答案 3 :(得分:0)

首先,对象必须是真正不可变的 - 不仅是公共接口,而且所有内部状态必须是初始化的。这禁止例如“获取一次缓存”或延迟初始化。

其次,在构造期间,对象被修改 - 并且由于CPU上的优化和指令重新排序,写入内存的顺序不一定与您在源代码中看到的顺序相同。

这意味着,在没有同步的情况下,另一个线程在完全构造之前可能已经看到对该对象的有效引用。

我对C#memroy模型不够熟悉,无法告诉您哪些同步是必要的 - 也许其他人可以提供帮助(制作社区维基)