Java 中的 Volatile 关键字 - 说明
我对我读到的有关 volatile 关键字在 java 中的应用的内容感到非常困惑。
下列说法正确的是? “对易失性字段的写入发生在同一字段的每次后续读取之前”
理想情况下何时应使用 易失性关键字?
有什么区别:
类测试类 { 私有 int x; 同步 int get(){return x;} 同步无效集(int x){this.x = x;} }
:和
class TestClass
{ private volatile int x;
int get(){return x;}
void set(int x){this.x = x;}
}
I am really confused about what I read about the applications of volatile keyword in java.
Is the following statement correct?
"a write to a volatile field happens before every subsequent read of the same field"Ideally when should volatile keyword used?
What is the difference between:
class TestClass { private int x; synchronized int get(){return x;} synchronized void set(int x){this.x = x;} }
and
class TestClass
{ private volatile int x;
int get(){return x;}
void set(int x){this.x = x;}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
易失性是字段修饰符,而同步修饰代码块和方法。因此,我们可以使用这两个关键字指定简单访问器的三种变体:
geti1()
访问当前线程中当前存储在i1
中的值。线程可以拥有变量的本地副本,并且数据不必与其他线程中保存的数据相同。特别是,另一个线程可能已在其线程中更新了
i1
,但其中的值当前线程可能与更新后的值不同。事实上,Java 有“主”内存的概念,这是保存变量当前“正确”值的内存。线程可以拥有自己的变量数据副本,并且线程副本可以与“主”内存不同。因此,事实上,i1
的“主”内存的值为 1,thread1 的值为 2 > 对于i1
和 thread2,如果 thread1,i1
的值为 3 > 和 thread2 都更新了 i1,但这些更新的值尚未传播到“主”内存或其他线程。另一方面,
geti2()
有效地从“主”内存访问i2
的值。不允许易失性变量拥有与“主”内存中当前保存的值不同的变量的本地副本。实际上,声明为 volatile 的变量必须使其数据在所有线程之间同步,以便每当您在任何线程中访问或更新该变量时,所有其他线程都会立即看到相同的值。通常,易失性变量比“普通”变量具有更高的访问和更新开销。通常,允许线程拥有自己的数据副本是为了提高效率。volile 和synchronized 之间有两个区别。
首先,synchronized 获取并释放监视器上的锁,该锁一次只能强制一个线程执行代码块。这是同步的众所周知的方面。但synchronized也同步内存。事实上,synchronized 使整个线程内存与“主”内存同步。因此,执行 geti3() 会执行以下操作:
因此,其中 volatile 只同步线程内存和“主”内存之间的一个变量的值,synchronized 同步线程内存和“主”内存之间的所有变量的值,并锁定和释放一个监视器以启动。显然,同步可能比易失性有更多的开销。
http://javaexp.blogspot.com/2007/12/difference -在-挥发性-和.html之间
volatile is a field modifier, while synchronized modifies code blocks and methods. So we can specify three variations of a simple accessor using those two keywords:
geti1()
accesses the value currently stored ini1
in the current thread.Threads can have local copies of variables, and the data does not have to be the same as the data held in other threads.In particular, another thread may have updated
i1
in it's thread, but the value in the current thread could be different from that updated value. In fact Java has the idea of a "main" memory, and this is the memory that holds the current "correct" value for variables. Threads can have their own copy of data for variables, and the thread copy can be different from the "main" memory. So in fact, it is possible for the "main" memory to have a value of 1 fori1
, for thread1 to have a value of 2 fori1
and for thread2 to have a value of 3 fori1
if thread1 and thread2 have both updated i1 but those updated value has not yet been propagated to "main" memory or other threads.On the other hand,
geti2()
effectively accesses the value ofi2
from "main" memory. A volatile variable is not allowed to have a local copy of a variable that is different from the value currently held in "main" memory. Effectively, a variable declared volatile must have it's data synchronized across all threads, so that whenever you access or update the variable in any thread, all other threads immediately see the same value. Generally volatile variables have a higher access and update overhead than "plain" variables. Generally threads are allowed to have their own copy of data is for better efficiency.There are two differences between volitile and synchronized.
Firstly synchronized obtains and releases locks on monitors which can force only one thread at a time to execute a code block. That's the fairly well known aspect to synchronized. But synchronized also synchronizes memory. In fact synchronized synchronizes the whole of thread memory with "main" memory. So executing
geti3()
does the following:So where volatile only synchronizes the value of one variable between thread memory and "main" memory, synchronized synchronizes the value of all variables between thread memory and "main" memory, and locks and releases a monitor to boot. Clearly synchronized is likely to have more overhead than volatile.
http://javaexp.blogspot.com/2007/12/difference-between-volatile-and.html
易失性
保证从变量读取的数据始终反映最新的更新值。运行时可以通过多种方式实现这一点,包括在值更改时不缓存或刷新缓存。volatile
guarantees that reads from the variable always reflects the most up to update value. The runtime can achieve this in various ways, including not caching or refreshing the cache when the value has changed.bwawok 避开了它,但 volatile 关键字不仅仅用于内存可见性。在 Java 1.5 发布之前,volatile 关键字声明该字段将通过每次读取时命中主内存和写入时刷新来获取对象的最新值。
今天的 volatile 关键字有两件非常重要的事情:
bwawok eluded to it, but the volatile keyword isnt only for memory visibility. Before Java 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.
Today's volatile keyword syas two very important things:
从客户端的角度来看,私有易失性字段对公共接口是隐藏的,而同步方法则更加可见。
From a client point of view, a private volatile field is hidden from the public interface while synchronized methods are more visible.
回答问题的第 3 部分和第 2 部分。
synchronized
和volatile
示例之间没有功能差异。然而,每种方法在性能方面都有其自身的缺点。在某些情况下,
易失性
性能可能比仅使用synchronized
或来自java.util.concurrent
的其他原语要差。有关此问题的讨论,请参阅 -> 为什么 Java 中的变量默认情况下不是 volatile?。To answer part 3 of your question, and partly part 2.
There is no functional difference between
synchronized
andvolatile
samples.However, each has it's own drawbacks in terms of performance. In some cases
volatile
performance may be really worse than just usingsynchronized
or other primitives fromjava.util.concurrent
. For discussion of this see -> Why aren't variables in Java volatile by default?.Kerem Baydoğan 的回答是完全正确的。我只想举一个实际的例子来说明
volatile
关键字为我们提供了什么。首先,我们有一个计数器,就像
一些可运行的任务,它会增加 x 的值,
如果没有同步,将会有 线程之间的干扰并且根本无法解决
这个问题的最简单方法:
实际上,为了强制系统中断,我做了一个
Thread。在读写
,想象一下是一个BD或者一个巨大的任务需要处理。x
之前sleep现在,
volatile
有什么用呢?那里有很多好文章: 易失性文章或这个问题< /a>同步对公共资源的访问不是答案,但
在我们的上一篇中保持标志以停止线程是一个不错的选择。例如,假设我们想要将变量增加到 100,一个简单的方法可能是使用
易失性布尔
标志。示例:这工作正常,但是,如果您从标志中删除
volatile
关键字,则可能会遇到无限循环。Answer by Kerem Baydoğan is completely right. I just want to give an practical example about what
volatile
keyword offers us.First, we have a counter, smth like
And some Runnable tasks which increments the value of x
With NO synchronization there is going to be interference between threads and simply is not going to work
the simplest way to solve this:
Actually in order to force the system to break, I do a
Thread.sleep
before reading and writingx
, just imagine is a BD or a huge task to deal with.Now, what is
volatile
useful for? There are a lot of good articles over there: volatile article or this questionsynchronizing the access to the common resource is not the answer but is a good choice to hold the flag to stop threads
I our prev. example, imagine we want to increment the variable up to 100, a simply way could be a
volatile boolean
flag. Example:This works fine, but, if you remove the
volatile
keyword from the flag, it's possible to come across and infinite loop.