Java 中的可变关键字 - 澄清
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3603157/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Volatile keyword in Java - Clarification
提问by devnull
I am really confused about what I read about the applications of volatile keyword in java.
我真的很困惑我读到的关于 java 中 volatile 关键字的应用程序的内容。
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;} }
以下说法正确吗?“写入易失性字段发生在每次后续读取同一字段之前”
理想情况下什么时候应该使用 volatile 关键字?
有什么区别:
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;}
}
回答by Kerem Baydo?an
volatileis a field modifier, while synchronizedmodifies code blocksand methods. So we can specify three variations of a simple accessor using those two keywords:
volatile是一个字段修饰符,而synchronized修改代码块和方法。因此,我们可以使用这两个关键字指定简单访问器的三种变体:
int i1;
int geti1() {return i1;}
volatile int i2;
int geti2() {return i2;}
int i3;
synchronized int geti3() {return i3;}
geti1()accesses the value currently stored in i1in 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 i1in 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 1for i1, for thread1 to have a value of 2for i1and for thread2to have a value of 3for i1if thread1and thread2have both updated i1 but those updated value has not yet been propagated to "main" memory or other threads.
geti1()访问当前存储在i1当前线程中的值。线程可以有变量的本地副本,并且数据不必与其他线程中保存的数据相同。特别是,另一个线程可能i1在其线程中进行了更新,但是当前线程中的值可能与其他线程中的值不同更新值。事实上,Java 有“主”内存的概念,这是保存变量当前“正确”值的内存。线程可以拥有自己的变量数据副本,并且线程副本可以与“主”内存不同。所以,事实上,它有可能为“主”内存有一个价值1对i1,i13对i1,如果线程1和线程2具有各自的i1,但这些更新的价值尚未被传播到“主”内存或其他线程。
On the other hand, geti2()effectively accesses the value of i2from "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.
另一方面,geti2()有效地访问i2来自“主”内存的值。不允许 volatile 变量具有与当前保存在“主”内存中的值不同的变量的本地副本。实际上,声明为 volatile 的变量必须在所有线程之间同步其数据,以便每当您在任何线程中访问或更新变量时,所有其他线程都会立即看到相同的值。通常 volatile 变量比“普通”变量具有更高的访问和更新开销。通常允许线程拥有自己的数据副本是为了提高效率。
There are two differences between volitile and synchronized.
volitile 和 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:
首先synchronized获取并释放监视器上的锁,一次只能强制一个线程执行一个代码块。这是同步的众所周知的方面。但同步也同步内存。事实上,synchronized 将整个线程内存与“主”内存同步。所以执行geti3()如下:
- The thread acquires the lock on the monitor for object this .
- The thread memory flushes all its variables, i.e. it has all of its variables effectively read from "main" memory .
- The code block is executed (in this case setting the return value to the current value of i3, which may have just been reset from "main" memory).
- (Any changes to variables would normally now be written out to "main" memory, but for geti3() we have no changes.)
- The thread releases the lock on the monitor for object this.
- 线程在监视器上获取对象 this 的锁。
- 线程内存刷新它的所有变量,即它的所有变量都有效地从“主”内存中读取。
- 执行代码块(在这种情况下,将返回值设置为 i3 的当前值,该值可能刚刚从“主”内存中重置)。
- (对变量的任何更改现在通常都会写出到“主”内存,但对于 geti3() 我们没有任何更改。)
- 该线程释放对象 this 的监视器上的锁。
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.
所以其中 volatile 只同步线程内存和“主”内存之间的一个变量的值,synchronized 同步线程内存和“主”内存之间所有变量的值,并锁定和释放监视器以启动。显然,同步可能比 volatile 有更多的开销。
http://javaexp.blogspot.com/2007/12/difference-between-volatile-and.html
http://javaexp.blogspot.com/2007/12/difference-between-volatile-and.html
回答by Steve Kuo
volatileguarantees 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.
volatile保证从变量中读取的值始终反映最新的更新值。运行时可以通过多种方式实现这一点,包括在值更改时不缓存或刷新缓存。
回答by John Vint
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.
bwawok 避开了它,但 volatile 关键字不仅仅用于内存可见性。在 Java 1.5 发布之前,volatile 关键字声明该字段将通过每次读取主内存和写入刷新来获取对象的最新值。
Today's volatile keyword syas two very important things:
今天的 volatile 关键字 syas 有两个很重要的事情:
- Dont worry about how but know that when reading a volatile field you will always have the most up to date value.
- A compiler cannot re order a volatile read/write as to maintain program order.
- 不要担心如何,但要知道在读取易变字段时,您将始终拥有最新的值。
- 编译器不能重新排序易失性读/写以维护程序顺序。
回答by Alexander Pogrebnyak
To answer part 3 of your question, and partly part 2.
回答您问题的第 3 部分和第 2 部分。
There is no functionaldifference between synchronizedand volatilesamples.
和样本之间没有功能差异。synchronizedvolatile
However, each has it's own drawbacks in terms of performance. In some cases volatileperformance may be really worse than just using synchronizedor other primitives from java.util.concurrent. For discussion of this see -> Why aren't variables in Java volatile by default?.
然而,每个人在性能方面都有自己的缺点。在某些情况下,volatile性能可能会比只使用可真是雪上加霜synchronized或其他原语java.util.concurrent。有关此问题的讨论,请参阅 ->为什么默认情况下 Java 中的变量不是 volatile?.
回答by Manu
Answer by Kerem Baydo?anis completely right. I just want to give an practical example about what volatilekeyword offers us.
Kerem Baydo?an 的回答是完全正确的。我只想举一个实际例子,说明volatile关键字为我们提供了什么 。
First, we have a counter, smth like
首先,我们有一个计数器,比如
public class Counter {
private int x;
public int getX() { return x; }
public void increment() { x++; }
}
And some Runnable tasks which increments the value of x
以及一些增加 x 值的 Runnable 任务
@Override
public void run() {
for (N) {
int oldValue = counter.getX();
counter.increment();
int new value = counter.getX();
}
}
}
With NO synchronization there is going to be interference between threadsand simply is not going to work
the simplest way to solve this:
解决这个问题的最简单方法:
public class Counter {
private int x;
public synchronized int getX() { return x; }
public synchronized void increment() { x++; }
}
Actually in order to force the system to break, I do a Thread.sleepbefore reading and writing x, just imagine is a BD or a huge task to deal with.
其实为了强制系统破解,我Thread.sleep在读写之前做了一个x,试想是一个BD还是一个巨大的任务要处理。
Now, what is volatileuseful for? There are a lot of good articles over there: volatile articleor this question
现在,有什么volatile用?那边有很多好文章:volatile 文章或者这个问题
synchronizing the access to the common resource is notthe 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 booleanflag. Example:
我我们的上一个 例如,假设我们想将变量增加到 100,一个简单的方法可以是一个volatile boolean标志。例子:
private volatile boolean stop;
@Override
public void run() {
while(!stop) {
int oldValue = counter.getX();
if (oldValue == 100) {
stop = true;
} else {
counter.increment();
int new value = counter.getX();
}
}
}
This works fine, but, if you remove the volatilekeyword from the flag, it's possible to come across and infinite loop.
这工作正常,但是,如果您volatile从标志中删除关键字,则可能会遇到无限循环。
回答by gawi
From a client point of view, a private volatile field is hidden from the public interface while synchronized methods are more visible.
从客户端的角度来看,一个私有的 volatile 字段对公共接口是隐藏的,而同步方法则更加可见。

