我是否也需要对引用类型的变量进行易失性?

2022-09-01 13:14:43

我们经常使用来确保条件变量对每个线程都可见。volatile

到目前为止,我看到这些字段都在代码中。volatileprimitive type

字段有此问题吗?例如:object

class a {

   public String str;

   public List list;

}

如果有一些线程可以访问 str 和 list,我必须添加“volatile”吗?

我猜每个访问都会直接从 获得,并且不会像基元类型那样缓存。ObjectHeapObject

是吗?


答案 1

您必须区分对象引用和实际对象。

  • 对于参考,您的字段修饰符是相关的。当您更改对其他对象的引用(即引用不同的字符串)时,其他 Thread 可能不会注意到更改。如果要强制实施可见性,则必须使用 或 。finalvolatile

  • 堆上的实际对象不受字段修饰符的影响。相反,您如何看待此对象的每个字段是由其自己的字段修饰符根据相同的规则确定的(是还是?如果不是,则不强制执行并发线程的可见性)volatilefinal

所以答案是:是的,你必须添加或。不过,从风格上讲,让这个领域成为决赛会好得多。它在线程方面具有相同的效果,但也是一个更强大的声明:此字段无法更改 - 这就是为什么JVM可以不顾一切地缓存它的原因。出于同样的原因,与 Java 相比,它带来了一点性能优势,Java 不需要关心字段是否再次更改,也不需要增加开销。volatilefinalvolatile


答案 2

添加以告诉编译器它绑定到 。以便所有线程都重新确认它们与原始线程相同,如果有更改,它会更新它。你发现它通常与基元,因为通常基元值被不同的线程递增或递减等。但是对象,特别是列表永远不会改变,因为它只是对对象的引用。如果要在运行时将不同的对象分配给同一变量,则可以这样做。volatile keywordchangelocal cached copy