Suppose two following counter implementations:
class Counter {
private final AtomicInteger atomic = new AtomicInteger(0);
private int i = 0;
public void incrementAtomic() {
atomic.incrementAndGet();
}
public synchronized void increment() {
i++;
}
}
At first glance atomics should be faster and more scalable. And they are, I believe. But are they faster than synchronized
blocks all the time? Or some situations exists when this rule is broken (e.g. SMP/Single CPU machine, different CPU ISA, OS'es etc.)?
The AtomicInteger class uses CAS (compare-and-swap) low-level CPU operations (no synchronization needed!) They allow you to modify a particular variable only if the present value is equal to something else (and is returned successfully).
Atomic variables help with handling non-atomic operations like increment-decrement, or any operations, which need to read the value before assigning a new one. Atomic values are a simple and convenient way to resolve synchronization issues in our code.
The volatile keyword is used: to make non atomic 64-bit operations atomic: long and double . (all other, primitive accesses are already guaranteed to be atomic!)
We can use the volatile keyword with variables. Using a volatile keyword with classes and methods is illegal. When we have our variables as volatile, they are always visible to other threads. If you declared the variable as volatile, Read and Writes are atomic.
incrementAndGet
may well be implemented as a CAS-loop. In highly contented situations that can result in n-1 of your threads failing leading to an O(n) problem, for n threads.
( For @Geek:
Typically getAndIncrement
may be implemented something like:
int old;
do {
old = value;
} while (!compareAndSet(value, old, old+1));
return old;
Imagine you have a n threads executing this code on the same atomic, and they happen to be in step with each other. The first iteration does kn work. Only one CAS will succeed. The other n-1 threads will repeat the exercise until there is only one left. So the total work is O(n^2) (worst case) instead of O(n). )
Having said that, acquiring a lock will need to do something similar at best, and locks aren't at their best when heavily contended. You're not likely to see much of an advantage for locks until you use a CAS-loop which requires significant computation before get and compareAndSwap.
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