[英]How can I use the volatile keyword in Java correctly?
说我有两个线程和一个对象。 一个线程分配对象:
public void assign(MyObject o) {
myObject = o;
}
另一个线程使用该对象:
public void use() {
myObject.use();
}
变量myObject是否必须声明为volatile? 我试图了解何时使用volatile而不是什么时候,这让我感到困惑。 是否有可能第二个线程在其本地内存缓存中保留对旧对象的引用? 如果没有,为什么不呢?
非常感谢。
我试图了解何时使用volatile而不是
你应该大多避免使用它。 改为使用AtomicReference (或适当的其他原子类)。 记忆效应是相同的,意图更清晰。
我强烈建议您阅读优秀的Java Concurrency in Practice以便更好地理解。
留下复杂的技术细节,你可以看到volatile
作为变量的synchronized
修饰符更少或更多。 当您想要同步访问方法或块时,您通常喜欢使用synchronized
修饰符,如下所示:
public synchronized void doSomething() {}
如果您想“同步”对变量的访问,那么您希望使用volatile
修饰符:
private volatile SomeObject variable;
在幕后他们做了不同的事情,但效果是一样的:对于下一个访问线程,更改立即可见。
在您的具体情况下,我认为volatile
修饰符没有任何价值。 volatile
不以任何方式保证分配对象的线程将在使用该对象的线程之前运行。 反过来也可以这样好。 您可能只想在use()
方法中首先执行nullcheck。
更新 :另见本文 :
对变量的访问就像包含在同步块中一样,自身同步。 我们在第二点说“就好像”,因为至少对程序员来说(并且可能在大多数JVM实现中) 没有涉及实际的锁对象 。
声明一个易变的Java变量意味着:
volatile的典型和最常见的用途是 :
public class StoppableThread extends Thread {
private volatile boolean stop = false;
public void run() {
while (!stop) {
// do work
}
}
public void stopWork() {
stop = true;
}
}
在这种情况下,您可以使用volatile。 您将需要围绕对变量或类似机制(如AtomicReference)的访问进行volatile,同步,以保证对赋值线程所做的更改实际上对读取线程可见。
我花了很多时间试图理解volatile
关键字。 我认为@aleroot已经给出了世界上最好,最简单的例子。
这反过来我对假人的解释(像我:-)):
场景1: 假设stop
没有被声明为volatile,那么给定的线程会做并“认为”以下内容:
stopWork()
:我必须将stop
设置为true
场景2: 现在让stop
声明为volatile :
stopWork()
:我必须将stop
设置为true
volatile
。 我必须占用CPU更长一点...... 没有同步,只是一个简单的想法......
为什么不在以防万一的情况下声明所有变量volatile
? 由于Scenario2 / Step3。 它有点低效但仍然比常规同步更好。
这里有一些令人困惑的评论:澄清,你的代码是不正确的 ,假设两个不同的线程调用assign()
和use()
。
在缺少volatile
或其他发生在之前的关系(例如,在公共锁上的同步)时,任何对assign()
myObject
写入都不能保证被调用use()
的线程看到 - 不是立即,不是及时的,真的不是永远的。
是的, volatile
是纠正这种情况的一种方法(假设这是不正确的行为 - 有可能的情况你不关心这个!)。
你是完全正确的'use'线程可以看到myObject
任何'缓存'值,包括它在构造时分配的值和任何中间值(再次没有其他发生前的点)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.