假设我有
private volatile AtomicInteger atomInt = new AtomicInteger(3);
在方法中我的用法是atomInt.incrementAndGet()
。
由于我使用AtomicInteger
,因此会避免"线程干扰"。然后我使用volatile,因此它将保证所有线程中变量的一致视图。这是否意味着我有完整的线程安全性,或者仍然存在内存一致性问题"?
我因使用"减少"而感到困惑。在tutorial,所以它告诉我仍有机会,但我无法想到它:
使用volatile变量可降低内存一致性的风险 错误,因为对volatile变量的任何写入都会建立一个 在与之后的相关读取之前发生 变量
答案 0 :(得分:2)
然后我使用
volatile
,因此它将保证所有线程中变量的一致视图。
原子变量已经保证了线程安全性。如果您不重新分配变量,则volatile
是多余的。您可以在此处将volatile
替换为final
:
private final AtomicInteger atomInt = new AtomicInteger(3);
这是否意味着我有完整的线程安全性或仍然存在“内存一致性问题”的可能性?
此时,它绝对是线程安全的。使用变量时,可能不会出现“内存一致性问题”。但是使用正确的线程安全组件并不意味着整个类/程序是线程安全的。如果它们之间的交互不正确,可能会出现问题。
使用volatile变量可降低内存一致性错误的风险......
volatile
个变量只能保证可见性。他们不保证atomicity。
正如Brian Goetz所写(强调我的):
volatile
变量很方便,但是它们有局限性。 volatile变量最常见的用途是完成,中断或状态标志。易失性变量可用于其他类型的状态信息,但尝试此操作时需要更加小心。例如,volatile
的语义不足以使增量操作(count++
)原子,除非您可以保证变量仅从单个线程写入只有满足以下所有条件时才能使用volatile变量:
- 写入变量不依赖于其当前值,或者您可以确保只有一个线程更新该值;
- 变量不参与其他状态变量的不变量;
- 访问变量时,出于任何其他原因不需要锁定。
来自java.util.concurrent.atomic
包的文档:
get
具有阅读volatile
变量的记忆效应。set
具有编写(分配)volatile
变量的记忆效应。
答案 1 :(得分:1)
易失性确实意味着变量的变化将是可见的。但在这种情况下,您不应该更改变量所持有的引用。
你想要引用一个原子对象volatile似乎很奇怪。 atomicinteger类的重点是提供一种安全访问和更改整数值的方法。使一些变量变为volatile的唯一原因是因为你打算覆盖它的值。为什么在可以使用其实例方法更新其值时覆盖对AtomicInteger的引用?
这就是为什么你得到建议让这个变量最终而不是volatile。使变量最终指向参考,以便它不会改变,同时确保该变量包含的引用是可见的。 atomicInteger以线程安全的方式管理自己的状态,因此您不必覆盖对它的引用。
所以说volatile在这里是多余的并不完全正确。但它正在做一些通常不应该做的事情。必须更改变量中包含的值时,请使用volatile。如果不应更改变量中包含的值,请使用final。