以下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(..)
可能必须执行的迭代次数可能很大,因为与添加两个int
s不同,BigInteger.add( BigInteger )
涉及许多步骤。
不,它不是原子的,但如果另一个线程修改了AtomicReference,那么compareAndSet调用将失败,它将再次循环,获取值,递增,然后尝试再次设置。它迟早(可能(会成功,并将AtomicReference持有的BigInteger更新为下一个数字。