for循环的每个循环都是原子操作吗



以下AtomicBigInteger实现的incrementAndGet方法是原子操作吗?我特别想知道for (; ; )部分。JVM是否以某种方式保证for循环中的每个循环都是原子执行的?

public final class AtomicBigInteger {
private final AtomicReference<BigInteger> valueHolder = new AtomicReference<>();
public AtomicBigInteger(BigInteger bigInteger) {
valueHolder.set(bigInteger);
}
public BigInteger incrementAndGet() {
for (; ; ) {
BigInteger current = valueHolder.get();
BigInteger next = current.add(BigInteger.ONE);
if (valueHolder.compareAndSet(current, next)) {
return next;
}
}
}
}

我从这里得到了这个代码:是否可以以线程安全的方式安全地增加BigInteger,也许可以使用AtomicReference,w/o锁定?然而,这种实施正在进行中,你可以在互联网上的许多不同地方找到它。

类中的方法incrementAndGet将不是原子方法。原因如下。

Atomic*类使用volatile值引用。这些值的内存偏移量也保存在实例中,它们可以使用这些实例在循环获取增量比较集,直到当前线程能够一次完成所有操作(即,没有另一个线程在其间执行增量(。

正如我所看到的,这对于这些Atomic*是可能的,因为访问内在的";"可信";类必须使用Unsafe实现。Unsafe实现具有使用native函数进行原子性比较和设置的方法。

在像您提到的情况下,我们将不得不使用synchronized块,即等效的基于Lock的实现,或者简单地使用AtomicReference中的方法。像这样:

public class AtomicBigInteger{
private final AtomicReference<BigInteger> valueHolder = new AtomicReference<>();
public AtomicBigInteger(BigInteger bigInteger) {
valueHolder.set(bigInteger);
}
public BigInteger incrementAndGet() {
return valueHolder.updateAndGet( bigInt -> bigInt.add( BigInteger.ONE ) );
} 
}

然而,由于我们正在处理BigInteger,因此也必须对该实现进行审查,因为AtomicReference.updateAndGet(..)可能必须执行的迭代次数可能很大,因为与添加两个ints不同,BigInteger.add( BigInteger )涉及许多步骤。

不,它不是原子的,但如果另一个线程修改了AtomicReference,那么compareAndSet调用将失败,它将再次循环,获取值,递增,然后尝试再次设置。它迟早(可能(会成功,并将AtomicReference持有的BigInteger更新为下一个数字。

相关内容

  • 没有找到相关文章

最新更新