AtomicInteger.updateAndGet()和AtomicInteger.accumulateAndGet()之间是否有任何功能差异?
问题描述:
是否有任何AtomicInteger.accumulateAndGet()
无法替换为AtomicInteger.updateAndGet()
的情况,还是只是方便参考?AtomicInteger.updateAndGet()和AtomicInteger.accumulateAndGet()之间是否有任何功能差异?
这里有一个简单的例子,我看不出有任何功能上的差异:
AtomicInteger i = new AtomicInteger();
i.accumulateAndGet(5, Math::max);
i.updateAndGet(x -> Math.max(x, 5));
显然,这同样适用于getAndUpdate()
和getAndAccumulate()
。
答
如果有疑问,你可以看看implementation:
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return next;
}
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}
他们一行只不同,显然accumulateAndGet
可以通过updateAndGet
简单地表示:
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
return updateAndGet(prev -> accumulatorFunction.applyAsInt(prev, x));
}
所以updateAndGet
是较为基本操作和accumulateAndGet
是一个有用的捷径。如果你的x
是不能有效地最终这种快捷方式可能会非常有用:
int nextValue = 5;
if(something) nextValue = 6;
i.accumulateAndGet(nextValue, Math::max);
// i.updateAndGet(prev -> Math.max(prev, nextValue)); -- will not work
答
在有些情况下可以使用accumulateAndGet
回避的实例创建情况。
这不是一个真正的功能差异,但它可能是有用的知道。
请看下面的例子:
void increment(int incValue, AtomicInteger i) {
// The lambda is closed over incValue. Because of this the created IntUnaryOperator
// will have a field which contains incValue. Because of this a new instance must
// be allocated on every call to the increment method.
i.updateAndGet(value -> incValue + value);
// The lambda is not closed over anything. The same IntBinaryOperator instance
// can be used on every call to the increment method, nothing need to be allocated.
i.accumulateAndGet(incValue, (incValueParam, value) -> incValueParam + value);
}
实例的作品一般都不贵,但也很重要的,是非常常用的性能敏感地点短操作摆脱。
有关何时重用lambda实例的更多信息,请参阅this answer。
是不是能够(重新)使用现有功能(或非捕获方法引用)的有用功能? 'i.incrementAndGet()'和'i.accumulateAndGet(1,Integer :: sum)'之间也没有功能上的区别...... – Holger
@Holger accumulateAndGet()'后来加了,再加上它不能使用'Unsafe'。 'addAndGet(1)'可能是一个更好的例子,但即使在创建时不使用“不安全”。不过,我确实接受你的一般观点;这个问题只是为了澄清这是否确实是动机。 – shmosel