为什么 Final 字段在 Java 中不能是易失性的?

2022-09-03 04:04:00

我想了解为什么声明为最终的引用不能声明为易失性。SO上也有类似的问题[为什么在Java中,对象成员变量不能既是最终的又是易失性的?

[1]:为什么Object成员变量在Java中不能既是最终的又是易失性的?但我不确定最终变量是否在这个答案中被理解。

现在,最终变量的状态在初始化后绝对可以更改。只有引用不能初始化为另一个对象。

例如,考虑以下成员变量

final StringBuilder sb = new StringBuilder("CAT");

现在另一个线程将 sb 更改为 :

sb.append("S");

如果此变量是非易失性变量,则此更改是否可用于每个 Java 内存模型的不同线程?

编辑:我将StringBuffer更改为StringBuilder,以便某些人明确我的观点。


答案 1

易失性意味着字段将发生变化。如果它是最终的,你永远不会改变它,这是没有意义的。

如果此变量是非易失性变量,则此更改是否可用于每个 Java 内存模型的不同线程?

声明字段易失性不会影响其内容或在易失性写入发生后的修改。如果字段是易失性的或非易失性的,则 的记忆效果由 StringBuffer 的实现决定。append

因此,在StringBuffer的情况下,它确实确保了内存可见性,但不是出于您认为的原因。StringBuffer是同步的(线程安全的),因此您将始终拥有最新的内容值。

另一方面,StringBuilder不同步,并且不能保证内存可见性。因此,如果您尝试将两者换成多线程测试,您将看到不同的结果。


答案 2

因为会影响线程访问和编辑变量的方式的行为。在代码示例中,变量是对对象的引用 ()。所以这个意思是对对象没有影响。 锁定引用。因此,如果追加文本,则不会更改引用。因此,同时使用和是没有意义的。volatilesbvolatilefinalvolatilefinal

如果此变量是非易失性变量,则此更改是否可用于每个 Java 内存模型的不同线程?

由于您使用的是 StringBuilder 的非线程安全实现,因此无法保证所有线程都具有 StringBuilder 的最新状态。


推荐