首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否保证处理后续网络请求的线程能够看到在前一个请求期间写入的易失性变量的值?

是否保证处理后续网络请求的线程能够看到在前一个请求期间写入的易失性变量的值?
EN

Stack Overflow用户
提问于 2020-02-28 07:50:18
回答 4查看 100关注 0票数 2

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

代码语言:javascript
复制
class MyHandlers {
  volatile int someFlag = 0;

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

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

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

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

注意:我理解,在实践中,处理第二个响应的线程总是将someFlag视为1。

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

附加思想(2020年3月2日): JMM没有提到时间的概念。同步操作是根据同步顺序排序的,但JMM中并没有说同步顺序与按时间排序的操作顺序相同。这意味着一个Java实现可以在someFlag 之前命令的读取,即使读取发生在之后,也可以按照时钟进行。似乎JMM只保证,如果的易失性读取是在易失性写入之后排序的,那么在易失性写入之前进行的写入对于易失性读取后的读取是可见的。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2020-03-17 03:36:43

我找到答案了!

Java语言规范第17.4.3节声明如下:

顺序一致性是程序执行过程中的可见性和顺序性的有力保证。在顺序一致的执行中,所有单个操作(例如读和写)都有一个与程序顺序一致的总顺序,每个单独的操作都是原子的,每个线程都可以立即看到

在Java内存模型中,“操作”指线程间操作,其中包括易失性写入。这一段保证任何符合JLS的Java实现都保证易失性写入将立即对其他线程可见。在开头的示例中,这一段保证在易失性写入之前不能对易失性读取进行排序。

票数 1
EN

Stack Overflow用户

发布于 2020-02-28 08:03:13

如果第一个请求完成,则意味着someFlag = 1已由某个线程执行。此时,someFlag的值可以保证在执行读取的任何其他线程中都是可见的。因此,当第二个请求出现时,您可以确保它的值为1。

票数 2
EN

Stack Overflow用户

发布于 2020-03-02 21:02:48

通常,每个线程在硬件中的某个地方都有自己的缓存。读和写通常是在这个缓存中进行的,稍后(当内存线需要离开缓存时),会被写回主内存。这就是为什么两个不同的线程可能会看到相同变量的不同值的原因。

volatile关键字可以防止这种情况发生。volatile值永远不会被缓存,所有的读和写都必须在主内存中完成。另外,volatile值也是原子式读写的。

因此,当第一个线程将someFlag更新为1时,所有线程都会立即看到它(由于缓存预防而降低了性能)。然后,当第二个线程读取它时,它将看到第一个线程给出的值。

由于客户端等待第一个请求的完成来启动第二个请求,所以您确定第一个请求发生在第二个请求之前。

将所有这些加在一起,第二个请求将无法将someFlag视为0。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60447379

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档