getter 方法是 Java 中 volatile 的替代方法吗?

Is getter method an alternative to volatile in Java?

我想知道私有布尔字段的 getter 方法是否会强制其他线程获取最新的更新值?这是 volatile 领域的替代品吗? 例如:

Class A {
    private boolean flag;

    public boolean getFlag() {
        return this.flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

Class B {
    public volatile boolean flag;
}

编辑: 是不是整个对象都被线程缓存了(包括私有字段),所以当我调用getter时它会return缓存的私有字段?

getter forces a thread to get an uncached value? Is this an alternative for volatile field?

不,getter 方法不强制执行任何操作,因此您必须需要一个 volatile 以便当前线程看到其他线程更新的最新值,否则,您可能会看到陈旧的价值观。

你需要了解以下来自here的文字,清楚地理解原子访问的概念。

volatile variable are always visible to other threads. It also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile

不,getter不会导致字段同步。

当谈到在多线程环境下读写原语时,我们遇到了三个问题,由 CPU

  1. 原子性:它可能需要多个汇编指令的存储或加载操作,例如,在 32 位 CPU 上写入 64 位整数。当前线程可能会在指令序列的中间被操作系统置于睡眠状态。
  2. 可见性:运行在一个核心上的线程可能无法读取来自其他核心的其他线程写入的最新值。仅仅因为 CPU 这么说。
  3. 重新排序:为了使程序 运行 更快,CPU 将汇编指令的顺序混合为它认为合适的顺序。

Getter 没有解决任何这些问题。即使是这样,JIT 编译器也可能会完全优化该函数。比什么?

Volatile是解决上述问题的方法之一。锁也是。它们确保一个线程读取原语的最新值,或确保正在写入的值对其他线程可见。它们还使汇编指令 运行 与编译时完全一样,没有任何混合。

附带说明一下,生成的程序集可能看起来与您在代码中编写的完全不同。你问自己 "I wrote in my code to read from flag, so why wouldn't the program read from the field itself?" 编译器可能会做任何它认为合适的事情来使汇编尽可能快。通过 not 添加任何锁或 volatile 说明符,您基本上告诉编译器不涉及多线程访问,并且编译器(以及随后的 CPU)可以自由假设该对象未被多个线程触及。可能一开始就没有创建这个对象。 JIT 编译器可能会说 "well, declare this boolean in a register and treat that as the entire object"。很有可能。

Edit: Is it true that the entire object is cached by a thread (including the private field), so that when I call the getter it will return the cached private field?

你不能这么想。这取决于 JVM,底层 OS 和底层 CPU。它可能被完全、部分或根本不缓存。提醒一下,大多数CPU的缓存行都不止一个,即使对象被缓存了,它缓存在哪里?在寄存器或缓存行之一中?

I'm wondering if a getter method for a private boolean field forces the other threads to get the latest updated value

没有。在没有 volatile 关键字的情况下,它不会强制其他线程获取最新值。

Is this an alternative for volatile field?

没有。在缺少 volatile 关键字的情况下,简单 getter 调用不能替代获取 boolean 值的最新值。

解决您问题的更好方法:使用AtomicBoolean

A boolean value that may be updated atomically. See the java.util.concurrent.atomic package specification for description of the properties of atomic variables.

几个更有用的链接:

Atomic package-summary

What is the difference between atomic / volatile / synchronized?

如果您对这两种方法使用同步关键字,则可以:

public synchronized boolean getFlag() {
    return this.flag;
}

public synchronized void setFlag(boolean flag) {
    this.flag = flag;
}

那么这两个方法相当于在实例变量上使用volatile