“挥发性”是什么意思?在Java中是什么意思?
我们在一个项目中使用 volatile 来维护不同线程访问的变量的相同副本。我的问题是是否可以将 volatile
与 static
一起使用。编译器没有给出任何错误,但我不明白使用两者的原因。
We use volatile
in one of our projects to maintain the same copy of variable accessed by different threads. My question is whether it is alright to use volatile
with static
. The compiler does not give any errors but I don't understand the reason of using both.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果没有阅读内存模型规范,我建议您阅读 http://jeremymanson.blogspot.com/2008/11/what-volatile-means-in-java.html。它是由 Java 内存模型 作者之一编写的,应该回答你的问题。根据 happens-before 子句来考虑内存读写也有帮助; Java 5 及以上版本的 JMM 向
易失性
添加了happens-before 语义。具体来说,当您从一个线程读取 易失性变量时,对该线程的所有写入(包括从其他线程对该易失性变量的写入)现在都对该线程可见。
是的,您可以使用
static
< /a> 与易失性
。他们做不同的事情。Short of reading the memory model specification, I recommend you read http://jeremymanson.blogspot.com/2008/11/what-volatile-means-in-java.html. It's written by one of the Java Memory Model authors and should answer your question. Thinking of memory reads and writes in terms of the happens-before clause is also helpful; the JMM for Java 5 onwards adds happens-before semantics to
volatile
.Specifically, when you read a volatile variable from one thread, all writes up to and including the write to that volatile variable from other threads are now visible to that one thread.
And, yes, you can use
static
withvolatile
. They do different things.易失性
表示变量在运行时发生变化,并且编译器不应出于任何原因缓存其值。只有在线程之间共享变量时,这才是真正的问题,您不希望线程使用过时的数据,因此编译器永远不应该缓存
易失性
变量引用的值。volatile
means that the variable changes at runtime and that the compiler should not cache its value for any reason.This is only really a problem when sharing the variable amongst threads, you don't want a thread working with stale data, so the compiler should never cache the value of a
volatile
variable reference.在 Java 中,易失性具有与 C 中类似的一般含义。 Java 内存模型 (请参阅 ide 的答案中的优秀链接)允许线程同时为标记为非易失性的变量“查看”不同的值。例如:
Thread a:
Threads B and C:
这个输出是允许发生的(注意,不能保证你严格地在 B 和 C 之间交替,我只是想在这里展示 B 和 C 的“转换”) :
这与
println
所获取的锁完全分开;即使 C 发现它是 2,线程 B 也被允许将n
视为 1。对此有很多很好的理由,但我无法假装完全了解了解,许多与速度有关,有些与安全有关。如果它是易失性的,那么可以保证(除了
println
的锁定,我暂时忽略它)B 和 C 都会“同时”看到 B 的新值正如它被发送一样。您可以将
volatile
与static
一起使用,因为它们会影响不同的事物。易失性
导致变量的更改在使用该变量之前被“复制”到所有使用该变量的线程,而static
在跨线程共享单个变量所有使用该变量的类。 (对于刚接触 Java 线程的人来说,这可能会相当令人困惑,因为每个Thread
碰巧都是作为一个class
实现的。)In Java, volatile has a similar general meaning as it does in C. The Java Memory Model (see the excellent link in ide's answer) allows threads to "see" a different value at the same time for variables marked as non-volatile. For example:
Thread a:
Threads B and C:
This output is allowed to happen (note that you're not guaranteed to strictly alternate between B and C, I'm just trying to show the "changeover" of B and C here):
This is entirely separate from the lock taken by
println
; thread B is allowed to seen
as 1 even after C finds out that it's 2. There are a variety of very good reasons for this that I can't pretend to fully understand, many pertaining to speed, and some pertaining to security.If it's volatile, you're guaranteed (apart from the
println
's locking, which I'll ignore for the moment) that B and C will both "simultaneously" see the new value of B as soon as it is sent.You can use
volatile
withstatic
because they affect different things.volatile
causes changes a variable to be "replicated" to all threads that use that variable before they use it, whilestatic
shares a single variable across all classes that use that variable. (This can be rather confusing to people new to threading in Java, because everyThread
happens to be implemented as aclass
.)考虑这样一个场景:两个线程(Thread1 和 Thread2)正在访问值为 1 的同一变量“mObject”。
当 Thread1 运行时,它不期望其他线程修改变量“mObject”。在这种情况下,Thread1 缓存了值为 1 的变量“mObject”。
如果 Thread2 将“mObject”的值修改为 2,Thread1 仍然会将 mObject 值引用为 1,因为它进行了缓存。
为了避免这种缓存,我们应该将变量声明为
private volatile int mObject;
在这种情况下,Thread1 将获取 mObject 的更新值
Consider a scenario when two thread (Thread1 and Thread2) are accessing same variable 'mObject' with value 1.
when a Thread1 runs, it doesn't expect other threads to modify the variable 'mObject'. In this scenario the Thread1 caches the variable 'mObject' with value 1.
And if the Thread2 modify the value of 'mObject' to 2, still the Thread1 would be refering the mObject value as 1 since it did caching.
To avoid this caching we should to declare the variable as
private volatile int mObject;
in this scenarion the Thread1 will be getting updated value of mObject
稍作阐述,但 volatile 关键字不仅仅用于内存可见性。在 Java 版本
1.5
发布之前,易失性关键字声明该字段将通过每次读取时命中主内存和写入时刷新来获取对象的最新值。在最新的 Java 版本中, volatile 关键字说了两件非常重要的事情:
您将始终拥有最新的价值。
查看更多 Java 易失性 示例。
Small elaboration, but the volatile keyword isn't just for for memory visibility. Before Java ver
1.5
was released the volatile keyword declared that the field will get the most recent value of the object by hitting main memory each time for reads and flushing for writes.In the latest Java versions, the volatile keyword says two very important things:
you will always have the most up to date value.
Check it out for more Java volatile examples.
Java volatile 关键字用于将 Java 变量标记为“正在存储在主内存中”。更准确地说,这意味着每次读取 易失性变量都会从计算机的主内存中读取,而不是从 CPU 缓存中读取,并且每次对易失性变量的写入都会写入主内存,而不仅仅是 CPU 缓存。属性的值不会在线程本地缓存,并且始终从“主内存”读取。
克服数据不一致问题是其优点,但读取和写入主存比访问 CPU 缓存的成本更高。因此,如果没有具体要求,不建议使用 volatile 关键字。
在上面的示例中,假设两个线程正在同一个类上工作。两个线程都在不同的处理器上运行,其中每个线程都有其 var 的本地副本。如果任何线程修改其值,则该更改不会反映在主内存中的原始值中。它会导致数据不一致,因为其他线程不知道修改的值。
在上面的示例中,易失性变量的值永远不会存储在缓存中。所有读取和写入都将在主存储器中完成。
The Java volatile keyword is used to mark a Java variable as "being stored in main memory". More precisely that means, that every read of a volatile variable will be read from the computer's main memory, and not from the CPU cache, and that every write to a volatile variable will be written to main memory, and not just to the CPU cache. The value of an attribute is not cached thread-locally, and is always read from the "main memory".
Overcoming the data inconsistency problem is the advantage but reading from and writing to main memory is more expensive than accessing the CPU cache. Hence, if there are no specific requirements it is never recommended to use volatile keywords.
In the above example, assume that two threads are working on the same class. Both threads run on different processors where each thread has its local copy of var. If any thread modifies its value, the change will not reflect in the original one in the main memory. It leads to data inconsistency because the other thread is not aware of the modified value.
In the above example, the value of a volatile variable will never be stored in the cache. All read and write will be done from and to the main memory.