[英]Atomic variables over Volatile
由于原子变量是易变的,即使您只需要易变性方面,始终使用原子变量是否有任何缺点?
变量不能是原子的。 原子性和易失性之间有明显的区别。
原子性:如果在给定时间只有一个线程可以执行一组指令,则该操作称为原子性。
易变:易变的性质确保了可见性。 如果一个线程修改了一些易失性状态,其他线程将获得最近更新的状态。
例子 :
volatile boolean flag;
public void flipTheFlag(){
if(flag == true){
flag = false;
}else{
flag = true;
}
}
如果多个线程正在执行flipTheFlag 操作,即使flag 是volatile 变量,flag 的值也会不确定。 这就是为什么操作 flipTheFlag 需要是原子的。 我们可以通过添加关键字“同步”来使 flipTheFlag 操作原子化。
当创建最终的Atomic对象后,不同的线程使用该对象来更改内部状态时,一切都像volatile 一样。
然而,周围有一个额外的对象实例。 消耗内存和速度性能。 在这种情况下,它应该是常量/有效最终的,并且它的创建应该在其他线程可以访问之前完成。
另一个方面 - 我实际上不记得从 java 参考中读取的正确性,但在其他地方读过 - 是有几个字段,当一个字段在修改时volatile
时,其他字段也将针对其他线程更新。
原子常量(或类似的 1 项常量数组)仍然具有可变状态,有时会被滥用以使用只能访问常量的Stream
操作来收集聚合结果。 这意味着Atomic
并不意味着多线程使用。
在x = x + c;
( volatile x
) 您将读取最新的x
,但是在添加c
,另一个线程可能会更改x
并且您仍然会为 x 分配一个陈旧的总和。 这里需要原子性。 或者if (x > 0) x = c;
.
所以要回答这个问题:根据脆弱的上下文,它们在某种程度上是可以互换的。 我可以理解您为什么更喜欢 Atomic,但在一些简单的情况下, volatile
性能要高得多,尤其是在细粒度并发中。
最后一句话:我不是完全有信心,我在这里是否完全正确。
从并发的角度来看,以下之间没有区别:
final AtomicInteger foo1 = new AtomicInteger();
和
volatile int foo2;
foo1.get/set 与 foo2 的读取和写入相同。 两者都将提供原子性、可见性和排序保证。 如果您查看例如 AtomicInteger 的代码,您将看到一个 volatile int 变量。
Atomic 的主要用例是很容易进行读修改写操作,例如增加计数器。 并且您可以访问更轻松的排序形式,例如 getRelease 和 setAcquire。 但是你可以使用 AtomicFieldReference 和 VarHandles 做同样的事情(虽然语法不太漂亮)。
atomic 的一个缺点是额外的内存使用和间接性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.