AtomicInteger.updateAndGet() 和 AtomicInteger.accumulateAndGet() 之间在功能上有什么区别吗?
Is there any functional difference between AtomicInteger.updateAndGet() and AtomicInteger.accumulateAndGet()?
有没有什么场景不能把AtomicInteger.accumulateAndGet()
换成AtomicInteger.updateAndGet()
,还是只是为了方法引用方便?
这是一个简单的示例,我没有发现任何功能差异:
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.
//
// It can be cached in a field, or maybe the optimizer is able
// to reuse it automatically.
IntBinaryOperator accumulatorFunction =
(incValueParam, value) -> incValueParam + value;
i.accumulateAndGet(incValue, accumulatorFunction);
}
实例创建通常并不昂贵,但对于在性能敏感位置非常频繁使用的短操作中摆脱它可能很重要。
有关何时重用 lambda 实例的更多信息,请参阅 this answer。
有没有什么场景不能把AtomicInteger.accumulateAndGet()
换成AtomicInteger.updateAndGet()
,还是只是为了方法引用方便?
这是一个简单的示例,我没有发现任何功能差异:
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.
//
// It can be cached in a field, or maybe the optimizer is able
// to reuse it automatically.
IntBinaryOperator accumulatorFunction =
(incValueParam, value) -> incValueParam + value;
i.accumulateAndGet(incValue, accumulatorFunction);
}
实例创建通常并不昂贵,但对于在性能敏感位置非常频繁使用的短操作中摆脱它可能很重要。
有关何时重用 lambda 实例的更多信息,请参阅 this answer。