今天工作时,我在Java中遇到了volatile关键字。不是很熟悉,我找到了这个解释。

鉴于那篇文章详细解释了所讨论的关键字,您曾经使用过它吗?或者您曾经看到过以正确方式使用该关键字的情况吗?


当前回答

如果您正在开发多线程应用程序,您将需要使用'volatile'关键字或'synchronized'以及您可能拥有的任何其他并发控制工具和技术。桌面应用就是这样一个例子。

If you are developing an application that would be deployed to application server (Tomcat, JBoss AS, Glassfish, etc) you don't have to handle concurrency control yourself as it already addressed by the application server. In fact, if I remembered correctly the Java EE standard prohibit any concurrency control in servlets and EJBs, since it is part of the 'infrastructure' layer which you supposed to be freed from handling it. You only do concurrency control in such app if you're implementing singleton objects. This even already addressed if you knit your components using frameworkd like Spring.

因此,在Java开发的大多数情况下,应用程序是一个web应用程序,并使用IoC框架,如Spring或EJB,你不需要使用'volatile'。

其他回答

Volatile具有内存可见性的语义。基本上,volatile字段的值在写操作完成后对所有读取器(特别是其他线程)可见。如果没有volatile,读者可以看到一些未更新的值。

回答您的问题:是的,我使用一个volatile变量来控制某些代码是否继续循环。循环测试易变值,如果为真则继续。可以通过调用“stop”方法将条件设置为false。循环看到false,并在stop方法完成执行后测试该值时终止。

我强烈推荐的《Java并发实践》一书对volatile做了很好的解释。这本书的作者与问题中提到的IBM文章的作者是同一人(事实上,他在那篇文章的末尾引用了他的书)。我对volatile的使用被他的文章称为“模式1状态标志”。

如果您想了解更多关于volatile在底层是如何工作的,请阅读Java内存模型。如果你想超越这个层次,看看像Hennessy & Patterson这样的优秀计算机体系结构书籍,阅读关于缓存一致性和缓存一致性的内容。

Volatile变量是轻量级同步。当所有线程之间的最新数据可见性是必需的,并且原子性可能会受到损害时,在这种情况下,Volatile变量必须是首选。对volatile变量的读取总是返回任何线程最近完成的写操作,因为它们既不缓存在寄存器中,也不缓存在其他处理器看不到的缓存中。Volatile是无锁的。当场景满足上面提到的条件时,我使用volatile。

挥发性

volatile -> synchronized[关于]

Volatile表示对于程序员来说,该值总是最新的。问题是该值可以保存在不同类型的硬件内存中。例如,它可以是CPU寄存器,CPU缓存,RAM…СPU寄存器和CPU缓存属于CPU,不能共享数据,不像RAM在多线程环境中处于抢救状态

volatile关键字表示变量将直接从/写入RAM内存。它有一些计算足迹

Java 5通过支持happens-before扩展volatile[关于]

对volatile字段的写入发生在后续每次读取该字段之前。

Read is after write

volatile关键字不能修复竞态条件[关于],使用synchronized关键字[关于]

因此,只有当一个线程写入,而其他线程只是读取volatile值时才安全

The volatile key when used with a variable, will make sure that threads reading this variable will see the same value . Now if you have multiple threads reading and writing to a variable, making the variable volatile will not be enough and data will be corrupted . Image threads have read the same value but each one has done some chages (say incremented a counter) , when writing back to the memory, data integrity is violated . That is why it is necessary to make the varible synchronized (diffrent ways are possible)

如果修改是由一个线程完成的,而其他线程只需要读取这个值,则volatile将是合适的。

从oracle文档页,需要volatile变量来修复内存一致性问题:

使用易失性变量可以降低内存一致性错误的风险,因为对易失性变量的任何写入都会与该变量的后续读取建立happens-before关系。

这意味着对volatile变量的更改总是对其他线程可见。这也意味着当线程读取一个volatile变量时,它不仅看到了volatile的最新更改,还看到了导致更改的代码的副作用。

正如在Peter Parker的回答中解释的那样,在没有volatile修饰符的情况下,每个线程的堆栈都可能有自己的变量副本。通过将变量设置为volatile,可以修复内存一致性问题。

为了更好地理解,请查看jenkov教程页面。

看一下相关的SE问题,了解更多关于volatile的细节和使用volatile的用例:

Java中volatile和synchronized的区别

一个实际的用例:

你有很多线程,它们需要以特定的格式打印当前时间,例如:java.text.SimpleDateFormat("HH-mm-ss")。可以有一个类,它将当前时间转换为SimpleDateFormat,并每一秒更新一次变量。所有其他线程都可以使用这个易失性变量在日志文件中打印当前时间。