Skip to content
Advertisement

Correct way to decrement an AtomicLong by a certain delta

Given an AtomicLong object, what is the right way to decrement the value by a delta?

Option 1

AtomicLong count = new AtomicLong(0L);

public void decrementCount(long decrementBy) {
       count.getAndUpdate(l->count.get() - decrementBy);
}

Option 2

AtomicLong count = new AtomicLong(0L);

public void decrementCount(long decrementBy) {
       count.getAndAdd(-decrementBy);
}

While both give the desired result, I want to understand under what circumstance will they not represent the desired behavior i.e to decrement a long value atomically? (One drawback of the second approach for example could be the negative sign causing some bit overflow but I am not sure if that’s true)

Advertisement

Answer

count.getAndUpdate(l->count.get() - decrementBy);

This doesn’t work atomically. getAndUpdate works roughly like this:

long getAndUpdate(LongUnaryOperator op) {
  long current;
  long newValue;
  do {
    current = this.get();
    newValue = op.apply(current);
  while (!compareAndSet(current, newValue));
  return current;
}

By re-reading count.get() inside the lambda, you’re reading the value of the AtomicLong then, which might be different to the value of current that it was passed, if some other thread updated the AtomicLong in between; you’d then update based on the updated value, not current.

Use the value you are passed in l:

count.getAndUpdate(l->l - decrementBy);

But getAndAdd(-decrementBy) is easier.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement