是否保证在另一个线程中看到一个线程中的非易失性成员变量的赋值?

Dar*_*ert 7 java multithreading java-memory-model

考虑下面的Java示例.请注意,两个类成员变量都没有声明为volatile.如果我正在理解内存模型并且"之前发生"规则正确,那么Java实现可以优化该run()方法,以便它永远运行,即使另一个线程调用该stopNow()方法.这可能发生,因为run()方法中没有任何内容强制线程stop多次读取值.那是对的吗?如果没有,为什么不呢?

class Example implements Runnable {
    boolean stop = false;
    int value = 0;

    public void stopNow() {
       stop = true;
    }

    public int getValue() {
        return value;
    }

    @Override
    public void run() {
        // Loop until stop is set to true.
        while (!stop) {
            ++value;
        }
        return;
    }
}
Run Code Online (Sandbox Code Playgroud)

sti*_*ike 4

可以由另一个线程修改,但这不是保证。这也不是线程安全的。要保证变量可以从另一个线程查看,您需要执行以下任一操作

\n\n
\n

仅在以下条件下,保证一个线程对字段所做的更改对其他线程可见:

\n\n
    \n
  • 写入线程释放同步锁,读取线程随后获取相同的同步锁。
  • \n
  • 如果一个字段被声明为易失性,则在写入器线程
    执行任何进一步的内存操作之前,写入该字段的任何值都会被写入器线程刷新并使其可见(即,出于当前的目的,
    它会立即刷新)。读取器线程必须
    在每次访问时重新加载易失性字段的 \n 值。
  • \n
  • 线程第一次访问对象的字段时,它会看到该字段的初始值或自某个其他线程写入以来的值。
  • \n
  • 当线程终止时,所有写入的变量都会刷新到主内存。例如,如果一个线程使用 Thread.join 在另一线程终止时进行同步,则可以保证看到
    该线程产生的效果(请参阅 \xc2\xa74.3.2)。
  • \n
\n
\n\n

有帮助的线程

\n

  • @DarylOdnert“*他编译器需要检查被调用的代码才能知道这样的优化是安全的*”=>不,它不会:内存模型允许不从内存中读取它,所以即使它会导致错误(我想这就是你对安全的定义)这是允许的。如果没有易失性,唯一的保证就是每个线程的程序顺序。 (2认同)
  • @DarylOdnert,如果一个方法修改了线程 T1 中的 stop ,那么该更改对于 T1 中运行的任何后续代码都是可见的 - 但这并不意味着该值是从内存中获取的...如果线程 T2 随后读取 stop ,它可能看不到新的价值。如果 T3 之前修改了停止,则 T1 可能看不到...... (2认同)