When exactly do you use the volatile keyword in Java?
我读过"何时使用Java中的‘易失性’?"但我还是很困惑。如何知道何时标记变量volatile?如果我弄错了,要么在需要它的东西上省略一个易失性,要么在不需要它的东西上加上易失性?在确定多线程代码中哪些变量应该是易失变量时,经验法则是什么?
你基本上使用它,当你想让一个成员变量是由多线程访问,但不需要的化合物的原子性(不确定,如果这是正确的术语)。
1 2 3 4 5 6 7 8 9 10 11 12 13 | class BadExample { private volatile int counter; public void hit(){ /* This operation is in fact two operations: * 1) int tmp = this.counter; * 2) this.counter = tmp + 1; * and is thus broken (counter becomes fewer * than the accurate amount). */ counter++; } } |
上面的例子是一个浴室,因为你需要化合物的原子性。
1 2 3 4 5 6 7 8 9 10 11 12 13 | class BadExampleFixed { private int counter; public synchronized void hit(){ /* * Only one thread performs action (1), (2) at a time *"atomically", in the sense that other threads can not * observe the intermediate state between (1) and (2). * Therefore, the counter will be accurate. */ counter++; } } |
现在一个有效的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class GoodExample { private static volatile int temperature; //Called by some other thread than main public static void todaysTemperature(int temp){ // This operation is a single operation, so you // do not need compound atomicity temperature = temp; } public static void main(String[] args) throws Exception{ while(true){ Thread.sleep(2000); System.out.println("Today's temperature is"+temperature); } } } |
现在,为什么你不能只是使用
这种均值,它甚至可能是你的应用程序。如果你的写作是一个
如果你把东西在
编辑:本评论反应:
Ok, but why can't we make todaysTemperature synchronized and create a synchronized getter for temperature?
你想和它的正确的行为。的东西,你可以与
波动是最有用的在无锁算法。你的共享可变数据作为标记持有挥发性当你不使用锁定访问变量的变化是由一个和你想在另一个线程是可见的,或你想创建一个"后发生的"关系到确保不重新计算一次,确保有序,在可见的变化。适当的时间。
《JMM食谱是运营了CAN的序,无法。
从Java并发教程:
Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable
号
这意味着对可变变量的更改对于其他线程总是可见的。它还意味着,当线程读取可变变量时,不仅可以看到可变变量的最新变化,还可以看到导致变化的代码的副作用。
关于您的查询:
How do I know when I should mark a variable volatile? What are the rules of thumb when figuring out what variables should be volatile in multithreaded code?
号
如果您觉得所有的读线程总是得到一个变量的最新值,那么您必须将该变量标记为
如果有一个编写器线程要修改变量的值,而有多个编写器线程要读取变量的值,那么volatile修饰符可以保证内存的一致性。
如果您有多个线程来写入和读取变量,那么仅使用
相关SE问题/文章:
Java文档中易失性变量的解释
Java中易失性与同步性的区别
javarevisited文章
在
这是一场declaring样
Java并发湖在实践上更多的主题。
实际上不同意上面的投票答案中给出的例子,据我所知,它没有正确地说明Java内存模型中的易失性语义。volatile的语义更加复杂。
在所提供的示例中,主线程可以永远继续打印"今天的温度为0",即使有另一个线程正在运行,如果另一个线程从未被调度过,则应该更新该温度。
用2个变量来说明易失性语义是一种更好的方法。
为了简单起见,我们假设更新这两个变量的唯一方法是通过方法"setttemperatures"。
为了简单起见,我们假设只有2个线程在运行,即主线程和线程2。
1 2 3 4 5 6 7 8 9 10 11 12 | //volatile variable private static volatile int temperature; //any other variable, could be volatile or not volatile doesnt matter. private static int yesterdaysTemperature //Called by other thread(s) public static void setTemperatures(int temp, int yestemp){ //thread updates yesterday's temperature yesterdaysTemperature = yestemp; //thread updates today's temperature. //This instruction can NOT be moved above the previous instruction for optimization. temperature = temp; } |
最后两个分配指令不能为优化目的被编译器、运行时或硬件重新排序。
1 2 3 4 5 6 7 |
号
一旦主线程读取挥发性可变温度(在打印过程中)。
1)可以保证它将看到这个易失性变量的最近写入值,不管向它写入多少线程,不管它们在哪个方法中更新、同步或不同步。
2)如果主线程中的system.out语句运行,在线程2运行语句temperature=temp的瞬间之后,昨天的温度和今天的温度都将保证在线程2运行语句temperature=temp时打印线程2设置的值。
如果a)多个线程正在运行,b)除了settemperatures方法外,还有其他方法可以更新变量昨天的温度和今天的温度,这些其他线程正在主动调用这些变量。我认为,根据Java内存模型如何描述易失性语义,将需要一个体面的文章来分析其含义。
简而言之,尝试只使用volatile进行同步是非常危险的,最好还是坚持同步方法。
mindprod.com http:/ / / / volatile.html jgloss
"在这动荡的关键字是特定变量可能被修改由其他线程。
"因为其他线程本地变量不能湖,那里没有任何需要标记的本地变量波动。你需要同步到坐标改变变量的波动往往从不同的线程,但想做只是看看他们。"
ValTale:意味着不断改变值。这个变量的值永远不会在本地缓存线程:所有的读写都直接进入"主内存"。换句话说,Java编译器和线程不缓存这个变量的值,并且总是从主内存读取它。