如何正确使用Java中的volatile关键字?

Tiy*_*oal 14 java volatile

说我有两个线程和一个对象.一个线程分配对象:

public void assign(MyObject o) {
    myObject = o;
}
Run Code Online (Sandbox Code Playgroud)

另一个线程使用该对象:

public void use() {
    myObject.use();
}
Run Code Online (Sandbox Code Playgroud)

变量myObject是否必须声明为volatile?我想知道什么时候使用volatile而什么时候不用,这让我很困惑.是否有可能第二个线程在其本地内存缓存中保留对旧对象的引用?如果没有,为什么不呢?

非常感谢.

Kev*_*vin 11

我试图了解何时使用volatile而不是

你应该大多避免使用它.改为使用AtomicReference(或适当的其他原子类).记忆效应是相同的,意图清晰.

我强烈建议您阅读优秀的Java Concurrency in Practice以便更好地理解.

  • 感谢您的建议.我同意我不必使用这些"低级别的东西".但是,我觉得有理由了解它是如何工作的.这本书是一个非常好的建议.谢谢. (2认同)
  • @Kevin:来自@Alerty的[this link](http://www.javamex.com/tutorials/synchronization_volatile.shtml)的引用:*"对变量**的访问就好像**它被包含在一个同步中阻止,自我同步."*,这基本上就是我在答案中要说的. (2认同)

Bal*_*usC 6

抛弃复杂的技术细节,您可以看到volatile更少或更多作为变量synchronized修饰符.当您想要同步访问方法或块时,您通常希望使用修饰符,如下所示:synchronized

public synchronized void doSomething() {}
Run Code Online (Sandbox Code Playgroud)

如果您想"同步"对变量的访问,那么您希望使用volatile修饰符:

private volatile SomeObject variable;
Run Code Online (Sandbox Code Playgroud)

在幕后他们做了不同的事情,但效果是一样的:对于下一个访问线程,更改立即可见.

在您的具体情况下,我认为volatile修饰符没有任何价值.在volatile不以任何方式将线程分配对象将运行保证之前使用该对象的线程.反过来也可以这样好.您可能只想先在use()方法中执行nullcheck .

更新:另见本文:

对变量的访问就像包含在同步块中一样,自身同步.我们在第二点说"好像",因为至少对程序员来说(并且可能在大多数JVM实现中)没有涉及实际的锁对象.

  • 这完全是错误的.易失性完全是关于变量的记忆效应和可见性,而不是并发访问. (7认同)
  • @Kevin:是的,这是技术细节.我在谈论**效果**,这对初学者来说更有意义.对于下一个访问线程,变量的更改立即可见. (3认同)