Reputation: 4949
I've been looking into the Java API java.util.concurrent.atomic, particularly the AtomicInteger class.
The method comments say that these methods are atomic.
Take getAndIncrement() for example:
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
which, as it is documented, is "Atomically increments by one the current value."
What exactly is making this method atomic? From what i see, it is completely "non-atomic"-- many cycles involved in its execution and, during the execution of the statement
int next = current + 1;
for instance, the value of next can be set by another thread.
Upvotes: 0
Views: 4404
Reputation: 527
If you trace the compareAndSet function implementation all the way to the assembly code you will find that it is translated into an single assembly instruction (cmpxchg for i486, in file linux_i486.s in sun jdk), which is a single instruction that does the exchange of values and hence providing the required atomicity as opposed to locking.
Upvotes: 0
Reputation: 2176
If you look at what could happen without loop and CAS, it will be clear what is meant by atomic here.
In the absence of synchronized and compare and set (so no need for loop), your code would be something like
public final int getAndIncrement() {
int current = get();
int next = current + 1;
set(next);
return current;
}
In a multithreaded environment, there could be two threads seeing the current value as 0 & trying to update the value to one. Two updates but value incremented by just one. Clearly without sychronization there is no guarantee that this can not happen.
So here is what compareAndSet helps, to see if the value is still zero before incrementing to one. So incaseof compareAndSet we say set the value to 1 only if the current value is zero, else fail. Considering above case of two threads updating the value, at most only one thread will successfully increase the value to 1 and other will fail. Thus honoring the Atomicity ('all or nothing') of the operation.
Upvotes: 0
Reputation: 1464
AtomicInteger uses combination of volatile & CAS (Compare and Swap) for thread-safe implementation of Integer Counter.
Read & write to volatile variables have same memory semantics as that of acquiring and releasing a monitor using synchronized code block. So the visibility of volatile field is guaranteed by the JMM.
AtomicInteger class stores its value field in a volatile variable, thus it is a decorator over the traditional volatile variable, but it provides unique non-blocking mechanism for updating the value after requiring the hardware level support for CAS (compare and set). Under low to moderate thread contention, atomic updates provides higher throughput compared to synchronized blocking increment operation.
Here is the implementation for getAndIncrement() method of AtomicInteger Class.
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}You can see that no lock is acquired to increment the value, rather CAS is used inside infinite loop to update the new value.
Since no locking is required by AtomicInteger, so it can be used to write scalable application where thread contention is low to medium.
Upvotes: 1
Reputation: 4319
The atomicity is handled whithin the compareAndSet(current, next)
method. The code does the incrementation and sets the new value only if it hasn't been changed yet, and that is done atomically (or it fakes the atomic behaviour). If it's been changed since then, it takes another try. So it might not be atomic, but it acts like it is.
Upvotes: 2