15

如果在 Java 中声明一个成员变量为 volatile,这是否意味着该对象的所有数据都存储在 volatile 内存中,或者该对象的引用存储在 volatile 内存中?

例如,如果我有以下课程:

class C{
   int i = 0;
   char c = 'c';
}

如果我声明它的一个实例如下:

private volatile C obj;

这会将引用存储obj在易失性内存中,还是将obj's 的数据(obj.iobj.c)存储在volatile内存中?

它是否使obj.c线程obj.i安全?

4

4 回答 4

27

是的,只有对象引用被 JVM 认为是易失的,而不是对象数据本身,它将驻留在堆上。如果您要求堆上对象的成员变量是易变的,您当然可以将关键字应用于这些原语

class C {
   volatile int i = 0;
   volatile char c = 'c';
}

回复:您关于这是否使变量线程安全的问题取决于您如何使用该变量。正如@gerrytan 从 Oracle 文档中指出的那样,volatile 关键字确实有助于读取或写入原子性,但是请注意,这与它始终是线程安全的不同。考虑以下代码...

if(obj != null) {
    obj.doSomething();
}

执行空检查的线程仍然有可能在执行之前被中断obj.doSomething(),而另一个线程设置obj = null。这里需要一些其他机制,例如synchronized块。

于 2013-03-18T21:54:24.193 回答
5
private volatile C obj;

那只会变得obj不稳定。

它是否使 obj.c 和 obj.i 线程安全?

不,要使它们成为线程安全的,您必须同步对它们的访问。

于 2013-03-18T21:49:59.907 回答
3

这只会使对象引用volatile。为了使 obj.i 和 obj.c 也易变,您必须明确地使它们易变

class C{
   volatile int i = 0;
   volatile char c = 'c';
}
于 2013-03-18T21:50:55.610 回答
1

如果在 Java 中声明一个成员变量为 volatile,这是否意味着该对象的所有数据都存储在 volatile 内存中,或者该对象的引用存储在 volatile 内存中?

当我们将对象声明为易失性时,我们实际上是在告诉底层处理器如何使用易失性对象。每次被 CPU 指令读取时,都会从堆中调用一个新副本,并且每次在对象上完成写入时都会保存它堆并可供其他线程使用。因此,处理器不会从缓存中选择旧值,也不会写入缓存并等待缓存写回堆。

它是否使 obj.c 和 obj.i 线程安全?不。它只是保证当你读取对象时你总是有一个新的副本。而且很有可能当你使用基于变量值的变量和处理逻辑时,有人可能已经在后台更改了值,当你更新它,你正在更新一个不同的值。

于 2013-05-14T10:06:55.657 回答