Twitter

Thursday, February 25, 2010

Optimistic CAS Vs Pessimistic synchronized...

As Brian Goetz says, be optimistic and not pessimistic.

Exclusive (synchronized) locking is pessimistic and CAS (compare-and-swap/set) used by AtomicInteger, AtomicLongs etcs are optimistic.

Synchronized (locking) is pessimistic in the sense that we fear that something can go wrong, so lock our stuff and do our work.

CAS is optimistic in the sense that we do some work optimistically and then try to commit our work. But if another guy has did what we did, we re-try to do our work once again.

More here in DeveloperWorks article on Going Atomic.

I wanted to see how CAS outperforms synchronized stuffs and the following code was the outcome.

Here we increment two variables with two different tasks.

The first task PlainIncrementTask increments the plain int of the Holder class using the custom-built synchronized getPlain() and incrementPlain() methods.

The second task AtomicIncrementTask increments the AtomicInteger of the Holder class using the AtomicInteger's incrementAndGet() and get() methods.

You can download the code here.

......
public int incrementAtomic() {
return atomicInteger.incrementAndGet();
}

public int getAtomic() {
return atomicInteger.get();
}

synchronized public int incrementPlain() {
return ++plainInteger;
}

synchronized public int getPlain() {
return plainInteger;
}
.....

And the results (of course) favour AtomicInteger.
mbp $ java Holder
Time taken for PLAIN: 1010 ms
Time taken for ATOMIC: 171 ms
mbp $ java Holder
Time taken for PLAIN: 1045 ms
Time taken for ATOMIC: 169 ms
mbp $ java Holder
Time taken for PLAIN: 1043 ms
Time taken for ATOMIC: 172 ms


So it is always better to use Atomic.* for counters and so on.

And never try to outperform the Java Gurus. ;)