Is there a way to perform a "decrement if result is positive or zero" operation with an AtomicInteger
?
To clarify the desired behavior:
In Java 8, yes:
atomicInteger.updateAndGet(i -> i > 0 ? i - 1 : i);
Before Java 8, no.
I suppose you could do something like this pre-Java 8:
int val = atomicInt.get();
boolean success = false;
while(val > 0 && !success) {
success = atomicInt.compareAndSet(val, val - 1);
if(!success) {
// Try again if the value is still > 0
val = atomicInt.get();
}
}
// Check 'success' to see if it worked
Not the most elegant code, but I think it does the trick.
Informal proof of correctness (by @Stephen C)
In the case where there is no other thread modifying the AtomicInteger
, success
will be set to true
on the first compareAndSet
call. So the code will be equivalent to
int val = atomicInt.get();
if (val > 0) {
atomicInt.compareAndSet(val, val - 1);
}
which is clearly correct.
In the case where some other thread modifies the AtomicInteger
, between the get
and the compareAndSet
then the latter call will fail because the current value is no longer equal to val
. So what happens then is that we call atomicInt.get()
again to get the updated value ... and repeat. We keep repeating until either we succeeded in the compareAndSet
OR the current val
is less zero or less.
The net effect is that this thread EITHER decrements the AtomicInteger
once, OR it gives up because it sees that the value is zero.
Note the following caveats:
AtomicInteger
after this sequence, you may observe that its value has changed ... again.AtomicInteger
.However, none of these caveats is a violation of the (assumed) requirements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With