2014-10-05 113 views
0

这个Q正在寻找关于Java如何使volatile字段可见的具体细节。Java如何管理易失性字段的可见性?

Java中的volatile关键字用于在完成对其的写入操作后,使该变量的读者“主动”可见的变量。这是发生之前关系的一种形式 - 使得写入结果暴露给访问该变量的内存位置以供某些用途的人。并且在使用时,对该变量进行读/写操作原子 - 对于long & double - 对于其他所有var类型的R/W已经是原子。

我期待找出Java那样做一个变量的值写入操作后看到什么呢?

例如:下面的代码是从this讨论其中一个答案:

public class Foo extends Thread { 
    private volatile boolean close = false; 
    public void run() { 
    while(!close) { 
     // do work 
    } 
    } 
    public void close() { 
    close = true; 
    // interrupt here if needed 
    } 
} 

读取和刻录布尔文字是原子。如果调用上述方法close(),它是一个原子操作来设置的close值作为true即使未声明为volatile

更何况volatile在此代码做的是确保更改这个值被认为是它发生的那一刻。

究竟如何volatile是实现这一目标?

通过对volatile变量优先与操作的线程?如果是这样 - 在线程调度中如何执行,或者通过使读取操作的线程查找标志来查看是否有写入器线程挂起?我知道“写入一个易失性字段发生在每次后续读取该字段之前”。它是否在线程中进行选择,在给只读的线程提供CPU时间之前,它对volatile变量有一个写操作?

如果这是在线程调度级别(我怀疑)中进行管理,那么在易失性字段上运行写入线程会比看起来效果更大。

究竟是如何被管理的Java变量volatile的知名度?

TIA。

+1

它保证一个线程写入到volatile变量将写入主存储器,并而不是处理器缓存,并且读取volatile变量值的线程不会从处理器缓存中读取,而是从主存储器中读取。我不是这些低级硬件机制的专家, LL让专家回答,但你应该明白我的意思,与调度或优先级无关。 – 2014-10-05 16:55:37

+0

的CPU完成所有的工作。在JVM确保它使用了正确的指示。 – 2014-10-05 17:36:01

回答

2

这是OpenJDK的源代码约挥发性

// ---------------------------------------------------------------------------- 
// Volatile variables demand their effects be made known to all CPU's 
// in order. Store buffers on most chips allow reads & writes to 
// reorder; the JMM's ReadAfterWrite.java test fails in -Xint mode 
// without some kind of memory barrier (i.e., it's not sufficient that 
// the interpreter does not reorder volatile references, the hardware 
// also must not reorder them). 
// 
// According to the new Java Memory Model (JMM): 
// (1) All volatiles are serialized wrt to each other. ALSO reads & 
//  writes act as aquire & release, so: 
// (2) A read cannot let unrelated NON-volatile memory refs that 
//  happen after the read float up to before the read. It's OK for 
//  non-volatile memory refs that happen before the volatile read to 
//  float down below it. 
// (3) Similar a volatile write cannot let unrelated NON-volatile 
//  memory refs that happen BEFORE the write float down to after the 
//  write. It's OK for non-volatile memory refs that happen after the 
//  volatile write to float up before it. 
// 
// We only put in barriers around volatile refs (they are expensive), 
// not _between_ memory refs (that would require us to track the 
// flavor of the previous memory refs). Requirements (2) and (3) 
// require some barriers before volatile stores and after volatile 
// loads. 

我希望这是有帮助的评论。

+0

你从哪儿 – Roam 2014-10-05 17:07:23

+0

@Roam得到这个,我与[OpenJDK](http://openjdk.java.net/)的来源以及[hotspot's]的这条评论一起工作(http://en.wikipedia.org/wiki/HotSpo t)口译员P.S.随时纠正我的英语 – Kastaneda 2014-10-05 17:31:02

+0

他们通常提供链接到一个来源在这里。通过它,如果不是秘密或任何东西 – Roam 2014-10-05 18:15:31

2

根据此:

http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile

Java的新的内存模型由

1做到这一点)从寄存器分配volatile变量禁止编译器和运行。

2)不允许编译器/优化器从代码重新排序字段访问。实际上,这就像获得一个锁。

3)强制编译器/运行时只要它被写入刷新从高速缓存的易失性可变到主存储器中。

4)在读取易失性字段之前将高速缓存标记为无效。

从文章:。

“挥发性字段被用于线程间通信状态的挥发性的每次读会被任何线程看到最后写入该挥发性特殊领域;实际上,他们被指定由程序员将其视为字段,因为缓存或重新排序的结果是看不到“过时的”值,编译器和运行时间禁止在寄存器中分配它们,还必须确保写入后它们是同时,在读取一个易失性字段之前,必须使缓存失效,以便主内存中的值(而不是本地处理器缓存)是唯一的值看到。还有另外一个l对重新排序访问volatile变量的限制。 “

... ”写入易失性字段与监视器版本具有相同的记忆效应,并且从易失性字段读取具有与监视器获取相同的记忆效应。实际上,因为新的内存模型放在挥发性场的重新排序严格限制访问与其他字段访问,挥发或不...”

+0

很好的答案+1。只需编辑第一个单词,写下“根据”而不是“ccording”。 – Alboz 2014-10-06 08:11:54

+0

是的。谢谢,修复它。 – 2014-10-06 08:31:24