问题
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.)?
回答1:
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.
回答2:
Or some situations exists when this rule is broken (e.g. SMP/Single CPU machine, different CPU ISA, OS'es etc.)?
I don't know of any. (And I stand ready to be corrected ... if someone knows of a concrete counter-example.)
However (and this is my main point) there is no theoretical reason why you couldn't have a hardware architecture or a poorly implemented JVM in which synchronized
is the same speed or faster than the atomic
types. (The relative speed of these two forms of synchronization is an implementation issue, and as such can only be quantified for existing implementations.)
And of course, this doesn't mean you should never use synchronized
. The synchronized
construct has many use-cases that the atomic classes don't address.
回答3:
It's implementation dependent - so ultimately you'll need to benchmark on your particualar platform / JVM / configuration.
Having said that, atomics should always be faster for the following reasons:
- Atomics are designed so that the JVM can take advantage of atomic machine instructions, which are the fastest atomic operations that you can get for most platforms
synchronized
makes use of relatively heavyweight locking schemes with monitor objects, which is designed to protect potentially large blocks of code. This form of locking in inherently more complicated than atomic operations so you would expect it to have higher runtime cost.
回答4:
As others have said this is implementation dependent . But keep in mind that if your program invariants involve more than one variable , then you have to use synchronization to update them together . You can't do atomic operation on two related variables together just because they are of Atomic type. In that case your only friend is synchronized .
回答5:
atomic variables will always be faster.
you can see that the java.util.concurrent package always utilises atomic variables rather than synchronized blocks.
来源:https://stackoverflow.com/questions/11551963/can-synchronized-blocks-be-faster-than-atomics