我们volatile
在我们的一个项目中使用来维护不同线程访问的变量的相同副本。我的问题是是否可以volatile
与static
. 编译器没有给出任何错误,但我不明白同时使用两者的原因。
5 回答
如果没有阅读内存模型规范,我建议您阅读http://jeremymanson.blogspot.com/2008/11/what-volatile-means-in-java.html。它由 JMM 的一位作者撰写,应该可以回答您的问题。根据happens-before子句考虑内存读取和写入也很有帮助;Java 5 及更高版本的 JMM 将happens-before 语义添加到volatile
.
具体来说,当您从一个线程读取 volatile 变量时,所有写入(包括从其他线程到该 volatile 变量的写入)现在对该线程可见。如果您有时间,可以通过 Google 技术讲座进一步讨论该主题:https ://code.google.com/edu/languages/#_java_memmodel 。
而且,是的,您可以使用static
with volatile
。他们做不同的事情。
volatile
意味着变量在运行时发生变化,并且编译器不应出于任何原因缓存其值。
这只是在线程之间共享变量时真正的问题,您不希望线程处理陈旧数据,因此编译器永远不应缓存volatile
变量引用的值。
在 Java 中,volatile 与在 C 中具有相似的一般含义。Java 内存模型(参见 ide 答案中的优秀链接)允许线程同时“看到”标记为非易失性变量的不同值。例如:
线程一:
n = 1;
// wait...
n = 2;
线程 B 和 C:
while (true) {
System.out.println(name + ": " + n);
}
允许发生此输出(请注意,您不能保证在 B 和 C 之间严格交替,我只是想在此处显示 B 和 C 的“转换”):
C: 1
B: 1
C: 2
B: 1
C: 2
B: 2
这与 ; 所采取的锁完全不同println
。即使在 C 发现它是 2 之后,线程 B仍被允许看到为 1。对此有很多很好的理由,我无法假装完全理解,其中许多与速度有关,还有一些与安全性有关。n
如果它是易变的,则可以保证(除了println
' 锁定,我将暂时忽略它) B 和 C 将在发送后立即“同时”看到 B 的新值。
您可以使用volatile
with,static
因为它们会影响不同的事物。 volatile
导致将变量更改为在使用该变量之前将其“复制”到使用该变量的所有线程,同时在使用该变量的所有类static
之间共享一个变量。(这对于刚接触 Java 线程的人来说可能是相当混乱的,因为每个都恰好被实现为.)Thread
class
考虑两个线程(Thread1 和 Thread2)正在访问值为 1 的相同变量“mObject”的场景。
当 Thread1 运行时,它不希望其他线程修改变量“mObject”。在这种情况下,Thread1 缓存了值为 1 的变量“mObject”。
如果 Thread2 将“mObject”的值修改为 2,那么 Thread1 仍然会将 mObject 值引用为 1,因为它进行了缓存。为了避免这种缓存,我们应该将变量声明为
私有易失性 int mObject;
在这种情况下,Thread1 将获得 mObject 的更新值
详细说明,但 volatile 关键字不仅仅用于内存可见性。在 Java1.5
版本发布之前,volatile 关键字声明该字段将通过每次读取主内存和写入刷新来获取对象的最新值。
在最新的 Java 版本中,volatile 关键字说明了两件非常重要的事情:
- 不要担心如何,但要知道,在读取 volatile 字段时,您将始终拥有最新的值。
- 编译器无法重新排序易失性读/写以维护程序顺序。
查看更多Java volatile示例。