首页 > 解决方案 > 处理后续网络请求的线程是否可以保证看到在先前请求期间写入的 volatile 变量的值?

问题描述

我有这个关于 Java 内存模型的理论问题。假设我在下面的类中有一个带有这两个请求处理程序的服务器:

class MyHandlers {
  volatile int someFlag = 0;

  String handleFirstRequest() {
    someFlag = 1;
    return "Hello!";
  }

  String handleSecondRequest() {
    return "value of someFlag: " + someFlag;
  }
}

我也有一个客户。我的客户端发送一个触发执行handleFirstRequest 的网络请求。客户端等待直到请求完成。一旦第一个请求完成,客户端发送触发 handleSecondRequest 的第二个请求。

问题: Java 内存模型如何防止对第二个请求的响应"value of someFlag: 0"

注意:我知道,在实践中,处理第二个响应的线程将始终someFlag显示为 1。

如果我正确读取了 JMM,则有一个同步顺序,即总顺序,someFlag = 1在我的示例中,它将对 volatile 读取和 volatile 写入 ( ) 进行排序。如果读取在写入之后,则读取将看到写入。是否有可能出现写入在读取之后的情况?在这种情况下,写入不会与读取同步,并且在写入和读取之间不会存在发生之前的关系。这将导致处理第二个请求的线程显示someFlag为 0。我的理解哪里出错了?

其他想法(2020 年 3 月 2 日): JMM 没有提到时间的概念。同步动作是根据同步顺序排序的,但 JMM 中没有任何内容说同步顺序与按时间排序的动作顺序相同。这表明 Java 实现可能会在写入someFlag 之前排序读取,即使根据时钟读取发生在写入之后。似乎 JMM 只保证如果volatile 读取是在 volatile 写入之后排序的,那么在 volatile 写入之前的写入对于 volatile 读取之后的读取是可见的。

标签: javamultithreadingvolatile

解决方案


如果第一个请求完成,则表示该请求someFlag = 1已被某个线程执行。此时,someFlag 的值保证对执行读取的任何其他线程可见。因此,当第二个请求到来时,您可以确定它会看到值 1。


推荐阅读