简体   繁体   中英

Can synchronized blocks be faster than Atomics?

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 (eg SMP/Single CPU machine, different CPU ISA, OS'es etc.)?

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.

Or some situations exists when this rule is broken (eg 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.

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.

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 .

atomic variables will always be faster.

you can see that the java.util.concurrent package always utilises atomic variables rather than synchronized blocks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM