Java Final 字段异端 : am I reasoning correctly?

标签 java c# thread-safety final

我最近开始学习C#,直接学习内存模型。 C# 和 Java 对于 volatile 字段的读取和写入具有类似(尽管可能不相同)的线程安全保证。但与 Java 中的 final 字段写入不同,C# 中的 readonly 字段写入不提供任何特定的线程安全保证。思考 C# 中线程安全的工作原理让我怀疑 final 字段的行为方式与 Java 中的方式是否有任何真正的优势。

三年前我了解到 final 的重要性。我问this question并得到了我接受的详细答案。但现在我认为这是错误的,或者至少是无关紧要的。我仍然认为字段应该尽可能是final,只是不是出于普遍认为的原因。

构造函数返回后,final 字段的值保证对任何其他线程可见。但对对象本身的引用必须以线程安全的方式发布。 如果引用安全发布,那么final的可见性保证就变得多余。

我考虑了它可能与公共(public)静态字段有关。但从逻辑上讲,类加载器必须同步类的初始化。同步使得final的线程安全变得多余。

所以我提出了一个异端的想法,即final的唯一真正值(value)是使不变性 self 记录和 self 执行。实际上,私有(private)非最终字段(尤其是数组元素)只要在构造函数返回后不被修改,就是完全线程安全的。

我错了吗?

编辑:释义《Java 并发实践》第 3.5 节,

Two things can go wrong with improperly published objects. Other threads could see a stale value for the reference, and thus see a null reference or other older value even though a value has been set. But far worse, other threads could see an up-to-date value for the reference, but stale values for the state of the object.

我了解 final 字段如何解决第二个问题,但不了解第一个问题。迄今为止得票最高的答案认为第一个问题不是问题。

编辑2:这个问题是由于术语困惑而产生的。

就像a similar question的提问者一样,我一直将术语“安全发布”理解为对象的内部状态对对象本身的引用保证对其他线程可见。为了支持这个定义,Effective Java 引用了 Goetz06, 3.5.3 将“安全发布”定义为(强调)

Transferring such an object reference from one thread to others

也支持这个定义,请注意上面解释的《Java 并发实践》部分将可能过时的引用称为“不正确发布”。

无论你怎么调用它,我认为不安全地发布对不可变对象(immutable对象)的引用可能会有用。但根据this answer , 它可以。 (给出的示例有一个原始值,但相同的原则也适用于引用值。)

最佳答案

But the reference to the object itself must be published in a thread safe manner. If the reference is published safely, then the visibility guarantee of final becomes redundant.

第一句话是错误的;因此,第二个是无关紧要的。在存在其他安全发布技术(例如同步或 volatile )的情况下,final 可能是多余的。但不可变对象(immutable对象)的要点是它们本质上是线程安全的,这意味着无论引用如何发布,它们都将处于一致的状态。因此,您首先不需要这些其他技术,至少就安全发布而言是这样。

编辑:OP正确地指出“安全发布”一词存在一些含糊之处。在这种情况下,我指的是对象内部状态的一致性。在我看来,影响引用的可见性问题是一个有效但单独的问题。

关于Java Final 字段异端 : am I reasoning correctly?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45928932/

相关文章:

c# - 在 ASP .NET MVC 中为静态资源启用 CORS?

java - ConcurrentModificationException 修复问题

java - 用 Java 存储可读可写的资源

java.lang.IllegalStateException : Not one of standard directories:/storage/emulated/0/Download/on Android 10

java - 使用java从日志文件中读取用户名

c# - 使用 C# 和 EPPlus 在 Excel 中卡住 Pane

java - 文本用户界面,无法使用方法

c# - .net/C# 的 Html 解析器和对象模型

java - JCheckBox.isSelected() 线程安全吗?

c# - 在没有锁的情况下读取 bool 属性时的线程安全