Есть ли функциональная разница между AtomicInteger.updateAndGet () и AtomicInteger.accumulateAndGet ()?
есть ли какой-либо сценарий, в котором AtomicInteger.accumulateAndGet()
нельзя заменить на AtomicInteger.updateAndGet()
, или это просто удобство для ссылки на метод?
вот простой пример, где я не вижу функциональной разницы:
AtomicInteger i = new AtomicInteger();
i.accumulateAndGet(5, Math::max);
i.updateAndGet(x -> Math.max(x, 5));
очевидно, то же самое касается getAndUpdate()
и getAndAccumulate()
.
2 ответов
когда вы сомневаетесь, вы можете посмотреть в реализация:
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 cashed in a field, or maybe the optimizer is able
// to reuse it automatically.
IntBinaryOperator accumulatorFunction =
(incValueParam, value) -> incValueParam + value;
i.accumulateAndGet(incValue, accumulatorFunction);
}
создание экземпляров, как правило, не дорого, но может быть важно избавиться от коротких операций, которые используются очень часто в чувствительных к производительности местах.
дополнительные сведения о том, когда экземпляры лямбда повторно используется можно найти в ответ.