【问题标题】:Declaring an object as volatile将对象声明为 volatile
【发布时间】:2013-03-07 10:08:02
【问题描述】:

如果在Java中将一个成员变量声明为volatile,这是否意味着该对象的所有数据都存储在易失性内存中,还是表示该对象的引用都存储在了易失性内存中?

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

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

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

private volatile C obj;

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

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

【问题讨论】:

标签: java multithreading volatile


【解决方案1】:

是的,只有对象引用会被 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 块。

【讨论】:

    【解决方案2】:
    private volatile C obj;
    

    这只会使obj volatile。

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

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

    【讨论】:

    • 这反映了一个类的instances 不是线程安全的一般原则; 是否是线程安全的。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      如果在Java中将一个成员变量声明为volatile,这是否意味着该对象的所有数据都存储在易失性内存中,还是表示该对象的引用都存储在了易失性内存中?

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-10
        • 2011-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多