首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >易挥发的与不易挥发的

易挥发的与不易挥发的
EN

Stack Overflow用户
提问于 2017-05-06 19:08:34
回答 2查看 244关注 0票数 1

让我们考虑一下Java中的以下代码

代码语言:javascript
复制
int x = 0;
int who = 1
Thread #1:
   (1) x++;
   (2) who = 2;

Thread #2
   while(who == 1);
   x++;   
   print x; ( the value should be equal to 2 but, perhaps, it is not* )    

(我不知道Java内存模型--假设它是强内存模型,我的意思是:(1)和(2)将不交换)

Java内存模型保证了对32位变量的访问/存储是原子的,因此我们的程序是安全的。但是,我们应该使用属性volatile,因为*。x的值可能等于1,因为xThread#2读取时可以保存在寄存器中。要解决这个问题,我们应该使x变量volatile。这是清楚的。

但是,这种情况是怎样的:

代码语言:javascript
复制
    int x = 0;
    mutex m; ( just any mutex)
Thread #1:
       mutex.lock()
       x++;
       mutex.unlock()

    Thread #2
       mutex.lock()
       x++;   
       print x; // the value is always 2, why**?
       mutex.unlock()

x的值始终是2,尽管我们没有使它成为volatile。我是否正确理解锁定/解锁互斥锁与插入内存屏障有关?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-05-06 21:19:25

我会试着解决这个问题。Java内存模型有点复杂,很难包含在一个StackOverflow帖子中。请参考Brian在实践中的Java并发性来了解整个故事。

X的值总是2,虽然我们不会使它不稳定。我是否正确理解锁定/解锁互斥锁与插入内存屏障有关?

首先,如果您想要理解Java内存模型,那么您希望阅读的始终是规范第17章

规范上写着:

监视器上的解锁发生在该监视器的每个后续锁之前。

所以是的,在显示器解锁时有一个内存可见事件。(我想“互斥”是指监视器。java.utils.concurrent包中的大多数锁和其他类也发生了--在语义之前,检查文档。

以前是Java的意思,它不仅保证事件有序,而且保证内存可见性得到保证。

代码语言:javascript
复制
We say that a read r of a variable v is allowed to observe a write w
to v if, in the happens-before partial order of the execution trace:

    r is not ordered before w (i.e., it is not the case that 
    hb(r, w)), and

    there is no intervening write w' to v (i.e. no write w' to v such
    that hb(w, w') and hb(w', r)).

Informally, a read r is allowed to see the result of a write w if there
is no happens-before ordering to prevent that read. 

这都是17.4.5写的。读起来有点让人困惑,但是如果你仔细阅读的话,所有的信息都在里面。

票数 3
EN

Stack Overflow用户

发布于 2017-05-06 20:09:43

我们来谈谈一些事情吧。以下语句是正确的: Java内存模型保证对32位变量的访问/存储是原子的。但是,并不意味着您列出的第一个伪程序是安全的。仅仅因为两个语句在语法上是有序的,并不意味着它们的更新的可见性也会像其他线程所看到的那样被排序。在x中的增量可见之前,线程#2可能会看到由who=2引起的更新。使x易失性仍然不能使程序正确。相反,让变量'who‘voliatile将使程序正确。这是因为易失性以特定的方式与java内存模型交互。

我觉得在对易失性的常识理解中,有一些“写回主记忆”的概念,这是不正确的。Volatile不将值写回Java的主内存。读取和写入易失性变量所做的是创建所谓的在关系之前发生的事情。当线程#1写入易失性变量时,您将创建一个关系,以确保查看该易失性变量的任何其他线程#2也能够“查看”线程#1之前所采取的所有操作。在你的例子中,这意味着让“谁”变得不稳定。通过将值2写入“您正在创建的是谁”--在关系发生之前--这样,当线程#2查看who=2时,它将类似地看到x的更新版本。

在您的第二个示例中(假设您也打算使用“who”变量),互斥锁会创建一个发生在前面的关系之前的关系。因为这意味着其他线程查看互斥锁的解锁(即。他们能够自己锁定它),他们将看到x的更新版本。

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

https://stackoverflow.com/questions/43824389

复制
相关文章

相似问题

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