如果在Java中将成员变量声明为volatile,这是否意味着所有对象的数据都存储在易失性存储器中,或者对象的引用存储在易失性存储器中?
例如,如果我有以下类:
class C{
int i = 0;
char c = 'c';
}
如果我按如下方式声明它的实例:
private volatile C obj;
是否将obj
的引用存储在易失性内存中,或obj
的数据(obj.i
和obj.c
)存储在volatile
内存中?
是否使obj.c
和obj.i
线程安全?
答案 0 :(得分:16)
是的,只有对象引用被JVM认为是易失性的,而不是将驻留在堆上的对象数据本身。如果您要求堆上对象的成员变量是volatile,您当然可以将关键字应用于这些原语
class C {
volatile int i = 0;
volatile char c = 'c';
}
Re:你是否使变量线程安全的问题取决于你如何使用变量。正如@gerrytan从Oracle文档中指出的那样,volatile关键字确实有助于读取或写入是原子的,但是请注意,这与它始终是线程安全的不同。请考虑以下代码......
if(obj != null) {
obj.doSomething();
}
执行空检查的线程仍然可能在执行obj.doSomething()
之前被中断,而另一个线程设置obj = null
。这里需要一些其他机制,例如synchronized
块。
答案 1 :(得分:3)
private volatile C obj;
这只会使obj
不稳定。
它是否使obj.c和obj.i线程安全?
没有。为了使它们具有线程安全性,您必须同步对它们的访问。
答案 2 :(得分:3)
这只会使对象引用 volatile 。 为了使obj.i和obj.c也 volatile ,你必须明确地将它们变为 volatile
class C{
volatile int i = 0;
volatile char c = 'c';
}
答案 3 :(得分:1)
如果在Java中将成员变量声明为volatile,这是否意味着所有对象的数据都存储在易失性存储器中,或者对象的引用存储在易失性存储器中?
当我们将对象声明为volatile时,我们实际上告诉底层处理器如何使用Volatile Object。每次CPU指令读取时都会从Heap调用一个新的副本,并且每次在对象上执行写操作它被保存到堆中并可供其他线程使用。因此,处理器不会从缓存旧值中选择,也不会写入缓存并等待缓存写回堆。
是否使obj.c和obj.i线程安全? 不。它只是保证当你阅读对象时你总是会有一个新的副本。当你使用基于可变量值的变量和处理逻辑时,很可能有人可能已经改变了背景中的值,当你更新它,您正在更新不同的值。