何时使用volatile
原语(例如boolean
,integer
或long
)代替AtomicBoolean
,AtomicInteger
或AtomicLong
,反之亦然?
答案 0 :(得分:17)
可见性语义完全相同,使用原子基元很有用的情况是当你需要使用它们的原子方法时。
例如:
if (volatileBoolean) {
volatileBoolean = !volatileBoolean;
}
可能会在多线程环境中产生问题,因为变量可能会在两行之间发生变化。如果您需要测试和分配是原子的,您可以使用:
atomicBoolean.compareAndSet(true, false);
答案 1 :(得分:15)
如果要设置或获取值,则使用普通的volatile更简单,更高效。 (但不能得到&设定值)
如果你想要更多的操作,比如getAndIncrement或compareAndSwap,你需要使用AtomicXxxx类。
答案 2 :(得分:8)
Atomic*
类包装了相同类型的volatile
基元。来自消息来源:
public class AtomicLong extends Number implements java.io.Serializable {
...
private volatile long value;
...
public final long get() {
return value;
}
...
public final void set(long newValue) {
value = newValue;
}
所以
何时使用volatile原语(例如boolean,integer或long)代替AtomicBoolean,AtomicInteger或AtomicLong
如果你所做的只是获取并设置Atomic*
,那么你也可以改为使用volatile
字段。
......反之亦然?
Atomic*
类为您提供的方法是提供更高级功能的方法,例如incrementAndGet()
,compareAndSet()
以及其他实现多个操作的方法(get / increment / set,test / set)没有锁定。这就是Atomic*
类如此强大的原因。
同样重要的是要注意,使用volatile
类包装Atomic*
字段是从对象角度封装关键共享资源的好方法。这意味着开发人员不能只处理该字段,假设它没有共享,可能会引入field++;
或引入竞争条件的其他代码的问题。
答案 3 :(得分:7)
我们已经开始禁止在我们的资源中使用volatile
,因为编写代码并不总是按预期工作。
根据我的经验,人们添加volatile来在线程之间共享一个值。然后,其他人开始修改该值。大多数时候,这都有效。但在生产中,你开始出现奇怪的错误,这些错误很难追查。计数器增加100'000次(测试只增加10次)但最终为99'997。在Java 1.4中,长值可能真的很少被破坏。
另一方面,Atomic*
帮助程序类只需要很小的开销,而且它们总是像宣传的那样工作。
因此,除非您有充分的理由(*)使用volatile
,否则请始终使用Atomic*
辅助类。
如果您不确切知道Atomic*
助手类中每个字符的确切含义,那么您应该完全避免使用volatile
。
*:过早优化绝不是一个好理由。