java - volatile 与非 volatile

标签 java multithreading shared-memory memory-barriers

让我们考虑以下 Java 代码

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,因为当Thread#2读取时,x可以保存在寄存器中.要解决这个问题,我们应该将 x 变量设为 volatile。很清楚。

但是,那种情况呢:

    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。我是否正确理解锁定/解锁互斥量与插入内存屏障有关?

最佳答案

我会尽力解决这个问题。 Java 内存模型有点复杂,很难包含在单个 StackOverflow 帖子中。请参阅 Brian Goetz 的 Java Concurrency in Practice 了解完整故事。

The value of x is always 2 though we don't make it volatile. Do I correctly understand that locking/unlocking mutex is connected with inserting memory barriers?

首先如果要了解Java内存模型,总是Chapter 17 of the spec你想通读。

该规范说:

An unlock on a monitor happens-before every subsequent lock on that monitor.

是的,在您的显示器解锁时会发生内存可见性事件。 (我假设“互斥锁”是指监视器。java.utils.concurrent 包中的大多数锁和其他类也有happens-before 语义,请查看文档.)

Happens-before 是 Java 的意思,它不仅保证事件有序,而且保证内存可见性。

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 .通读起来有点困惑,但如果您通读它,信息就在那里。

关于java - volatile 与非 volatile ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43824389/

相关文章:

java - 寻求Java内置Object类的解释

java - 使用 JComboBox 选择后 JPanel 不刷新

c - 在驻留在不同套接字上的处理器之间共享数据的最快方法

multithreading - 字符串与整数作为 golang 中内存利用率的映射键?

c - 具有非空 shmaddr 的 Shmat

c - 使用 mmap 从共享内存中读取 - 段错误

java - 重新加载 jsf 表单错误上的某个 jQuery 代码

java - 如何在android studio 1.1.0中添加库

c# - 通过引用传递的多个线程访问的静态方法

python - 如何在 Python 中配置 `/dev/shm/` 或 `_multiprocessing.SemLock` 的替代方案