首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >深入理解Java中的易失性

深入理解Java中的易失性
EN

Stack Overflow用户
提问于 2017-07-16 22:29:02
回答 4查看 273关注 0票数 3

Java允许输出1, 0吗?我已经对它进行了非常深入的测试,但我无法得到这个输出。我只得到1, 10, 00, 1

代码语言:javascript
运行
复制
public class Main {
    private int x;
    private volatile int g;

    // Executed by thread #1
    public void actor1(){
       x = 1;
       g = 1;
    }

    // Executed by thread #2
    public void actor2(){
       put_on_screen_without_sync(g);
       put_on_screen_without_sync(x);
    }
}

为什么?

在我看来,获得1, 0是可能的。我的推理。g是不稳定的,因此它会导致内存顺序得到保证。所以,看起来:

代码语言:javascript
运行
复制
actor1:

(1) store(x, 1)
(2) store(g, 1)
(3) memory_barrier // on x86

并且,我看到了以下情况:在store(x,1)之前重新排序store(x,1) (memory_barrier是(2)之后的)。现在,运行线程#2。那么,g = 1, x = 0。现在,我们已经预计到了产出。我的推理有什么不正确的?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-07-16 22:43:18

在易失性写入之前的任何操作都发生在(HB)之前,也就是相同变量的任何后续易失性读取。在您的示例中,对x的写入发生在写入g之前(由于程序顺序)。

所以只有三种可能性:

  • actor2首先运行,x和g为0-输出为0。
  • actor1首先运行,x和g是1,因为在HB -输出关系为1,1之前发生了这种情况。
  • 方法同时运行,只执行x=1 (而不是g=1),输出可以是0,1或0,0 (没有易失性写入,因此不能保证)。
票数 2
EN

Stack Overflow用户

发布于 2017-07-16 22:47:21

不,这不可能。根据JMM,当线程1写入易失性字段时,线程1可以看到的任何内容在读取该字段时对线程2都是可见的。

还有另一个类似于您的在此提供的例子

代码语言:javascript
运行
复制
class VolatileExample {
  int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    v = true;
  }

  public void reader() {
    if (v == true) {
      //uses x - guaranteed to see 42.
    }
  }
}
票数 2
EN

Stack Overflow用户

发布于 2020-11-30 17:13:28

您将永远不会看到1, 0,但是正确地解释这一点并不容易,规范是明智的。首先,让我们把一些显而易见的东西从门里拿出来。规范他说

如果x和y是同一个线程的动作,x以程序顺序在y之前,则hb(x,y)。

这意味着在写入线程端、hb(x, g)和读取端hb(g, x)。但是,只有在您必须对每个线程说:进行推理的情况下,情况才会如此。

在每个线程执行的所有inter-thread操作中.

因此,如果您设想一次运行每个线程,那么happens-before对每个线程都是正确的。但是你没有。你的演员(我相信你在那里使用jcstress )同时运行。因此,仅仅依靠“程序顺序”进行推理是不够的(两者都不正确)。

你需要在某种程度上同步这两个动作--读和写。这是规格说明是怎么做的?

对易失性变量synchronizes-with的写入(所有后续的线程都会读取v)(其中“后继”是根据同步顺序定义的)。

后来说:

如果一个动作x synchronizes-with是跟随动作y,那么我们也有hb(x,y)。

如果你现在把所有这些放在一起:

代码语言:javascript
运行
复制
          (hb)              (hb)             (hb)
write(x) ------> write(g) -------> read(g) -------> read(x)

这也被称为“临时”关闭program ordersynchronizes-with order。由于每一步都有hb,根据规范,不可能看到1, 0 (一个生动的阅读)。

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

https://stackoverflow.com/questions/45133832

复制
相关文章

相似问题

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