I can see that ReentrantLock is around 50% faster than synchronized and AtomicInteger 100% faster. Why such difference with the execution time of these three synchronization methods: synchronized blocks, ReentrantLock and AtomicInteger (or whatever class from the Atomic package).
Are there any other popular and extended synchronizing methods aside than these ones?
A number of factor effect this.
the version of Java. Java 5.0 was much faster for ReentrantLock, Java 7 not so much
the level of contention. synchronized works best (as does locking in general) with low contention rates. ReentrantLock works better with higher contention rates. YMWV
how much optimisation can the JIT do. The JIT optimise synchronized in ways ReentrantLOck is not. If this is not possible you won't see the advantage.
synchronized is GC free in it's actions. ReentrantLock can create garbage which can make it slower and trigger GCs depending on how it is used.
AtomicInteger uses the same primitives that locking uses but does a busy wait. CompareAndSet also called CompareAndSwap i.e. it is much simpler in what it does (and much more limited as well)
The ConcurrentXxxx, CopyOnWriteArrayXxxx collections are very popular. These provide concurrency without needing to use lock directly (and in some cases no locks at all)
AtomicInteger is much faster than the other two synchronization methods on your hardware because it is lock-free. On architectures where the CPU provides basic facilities for lock-free concurrency, AtomicInteger's operations are performed entirely in hardware, with the critical usually taking a single CPU instruction. In contrast, ReentrantLock and synchronized use multiple instructions to perform their task, so you see some considerable overhead associated with them.
I think that you are doing a common mistake evaluating those 3 elements for comparison.
Basically when a ReentrantLock is something that allows you more flexibility when your are synchronizing blocks compared with the synchronized key. Atomic is something that adopts a different approach based on CAS(Compare and Swap) to manage the updates in a concurrent context.
I suggest you to read in deep a bible of concurrency for the Java platform.
Java Concurrency in Practice - Brian Göetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes & Doug Lea
There's a lot difference in having a deep knowledge on concurrency and know what a language can offer you to solve concurrency problems and taking advantage of multithreading.
In terms of performance, it depends on the current scenario.
Related
Is there a difference between 'ReentrantLock' and 'synchronized' on how it's implemented on CPU level?
Or do they use the same 'CAS' approach?
If we are talking about ReentrantLock vs synchronized (also known as "intrinsic lock") then it's a good idea to look at Lock documentation:
All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock:
A successful lock operation acts like a successful monitorEnter
action
A successful unlock operation acts like a successful monitorExit
action
So in general consider that synchronized is just an easy-to-use and concise approach of locking. You can achieve exactly the same synchronization effects by writing code with ReentrantLock with a bit more code (but it offers more options and flexibility).
Some time ago ReentrantLock was way faster under certain conditions (high contention for example), but now Java uses different optimizations techniques (like lock coarsening and adaptive locking) to make performance differences in many typical scenarios barely visible to the programmer.
There was also done a great job to optimize intrinsic lock in low-contention cases (e.g. biased locking). Authors of Java platform do like synchronized keyword and intrinsic-locking approach, they want programmers do not fear to use this handy tool (and prevent possible bugs). That's why synchronized optimizations and "synchronization is slow" myth busting was such a big deal for Sun and Oracle.
"CPU-part" of the question:
synchronized uses a locking mechanism that is built into the JVM and MONITORENTER / MONITOREXIT bytecode instructions. So the underlying implementation is JVM-specific (that is why it is called intrinsic lock) and AFAIK usually (subject to change) uses a pretty conservative strategy: once lock is "inflated" after threads collision on lock acquiring, synchronized begin to use OS-based locking ("fat locking") instead of fast CAS ("thin locking") and do not "like" to use CAS again soon (even if contention is gone).
ReentrantLock implementation is based on AbstractQueuedSynchronizer and coded in pure Java (uses CAS instructions and thread descheduling which was introduced it Java 5), so it is more stable across platforms, offers more flexibility and tries to use fast CAS appoach for acquiring a lock every time (and OS-level locking if failed).
So, the main difference between these locks implementations in terms of performance is a lock acquiring strategy (which may not exist in specific JVM implementation or situation).
And there is no general answer which locking is better + it is a subject to change during the time and platforms. You should look at the specific problem and its nature to pick the most suitable solution (as usually in Java)
PS: you're pretty curious and I highly recommend you to look at HotSpot sources to go deeper (and to find out exact implementations for specific platform version). It may really help. Starting point is somewhere here: http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/runtime/synchronizer.cpp
The ReentrantLock class, which implements Lock, has the same concurrency and memory semantics as synchronized, but also adds features like lock polling, timed lock waits, and interruptible lock waits. Additionally, it offers far better performance under heavy contention.
Source
Above answer is extract from Brian Goetz's article. You should read entire article. It helped me to understand differences in both.
I've been using ReadWriteLock`s to implement/maintain a locking idioms.
Since JDK8 StampedLock has been introduced. And as RWLocks are known with their slowness and bad performance, StampedLock's look like an alternative (they are not reentrant, so much faster).
However except the performance, it looks to me that StampedLock's are much harder and complex to maintain and use - e.g. threads can now deadlock against themselves - so corresponding actions should be taken.
What are the benefits of StampedLock over RWLock ?
This article explains the differences in detail.
The ReentrantReadWriteLock had a lot of shortcomings: It suffered from starvation. You could not upgrade a read lock into a write lock. There was no support for optimistic reads. Programmers "in the know" mostly avoided using them.
Doug Lea's new Java 8 StampedLock addresses all these shortcomings. With some clever code idioms we can also get better performance.
Well, yes ReentrantReadWriteLock had problems (when compared to the traditional synchronized block) in 5.0 but they fixed it in java 6.0.
So, if you guys use Java 6 in production, you can use the lock API with confidence.
Performance wise lock & traditional synchronization gives you same.
The good thing about lock API is that it uses CAS/non-blocking so it will never end up with deadlock unless you forget to unlock it in the finally block.
From the Performance and Scalability chapter of the JCIP book:
The synchronized mechanism is optimized for the uncontended
case(volatile is always uncontended), and at this writing, the
performance cost of a "fast-path" uncontended synchronization ranges
from 20 to 250 clock cycles for most systems.
What does the author mean by fast-path uncontended synchronization here?
There are two distinct concepts here.
Fast-path and Slow-path code
Uncontended and Contended synchronization
Slow-path vs Fast-path code
This is another way to identify the producer of the machine specific binary code.
With HotSpot VM, slow-path code is binary code produced by a C++ implementation, where fast-path code means code produced by JIT compiler.
In general sense, fast-path code is a lot more optimised. To fully understand JIT compilers wikipedia is a good place to start.
Uncontended and Contended synchronization
Java's synchronization construct (Monitors) have the concept of ownership. When a thread tries to lock (gain the ownership of) the monitor, it can either be locked (owned by another thread) or unlocked.
Uncontended synchronization happens in two different scenarios:
Unlocked Monitor (ownership gained strait away)
Monitor already owned by the same thread
Contended synchronization, on the other hand, means the thread will be blocked until the owner thread release the monitor lock.
Answering the question
By fast-path uncontended synchronization the author means, the fastest bytecode translation (fast-path) in the cheapest scenario (uncontended synchronization).
I'm not familiar with the topic of the book, but in general a “fast path” is a specific possible control flow branch which is significantly more efficient than the others and therefore preferred, but cannot handle complex cases.
I assume that the book is talking about Java's synchronized block/qualifier. In this case, the fast path is most likely one where it is easy to detect that there are no other threads accessing the same data. What the book is saying, then, is that the implementation of synchronized has been optimized to have the best performance in the case where only one thread is actually using the object, as opposed to the case where multiple threads are and the synchronization must actually mediate among them.
The first step of acquiring a synchronized lock is a single volatile write (monitor owner field). If the lock is uncontested then that is all which will happen.
If the lock is contested then there will be various context switches and other mechanisms which will increase clock cycles.
I am carrying out an experiment with two multithreading java programs. I have one that is not synchronized and another that is using AtomicInteger. The AtomicInteger is much slower. I think this might be because of the method AtomicInteger uses compareAndset(). Am I correct?
Of course, the safety of synchronization comes with some performance cost. For example, see Cost of synchronization.
The AtomicInteger class and its siblings will be as fast as any equivalent functionality you can write in pure Java, and will often be faster, because they are likely to be able to use native instructions available on the platform.
Whenever you are writing a concurrent program, use the java.util.concurrency package. It's more robust and more efficient than anything you'll write with synchronized or volatile.
An operation by one thread is only guaranteed to be visible to another thread if both threads use suitable memory barriers. For example, writing and reading a volatile variable, or entering a synchronized block. Skipping memory barriers will be faster, but since your program is broken, your efficiency is zero.
I've come across these two in some multi-threaded code and was wondering if there is if/any difference between the two.
I mean does the use of an AtomicBoolean, rather than a SynchronizedBoolean, make a
significant difference in performance?
And does it affect the correctness of the computation?
AtomicBoolean is a part of the standard java concurrent package. SynchronizedBoolean is part of a set of utilities created by Doug Lea (author of much of the java concurrent packages). Performance-wise, you should expect AtomicBoolean to perform better -- it uses a volatile boolean whereas SynchronizedBoolean uses a ReadWriteLock.
However in practice for most applications you won't notice much difference.
The real difference (and what should guide your choice) is in the semantics the two classes offer. AtomicBoolean provides just simple set/get/compareAndSet operations. The SynchronizedBoolean offers atomic boolean operations and exposes its internal lock to allow you to execute Runnables within the context of its value.
Doug Lea has offered this source free to the community. I have found an extension to SynchronizedBoolean, WaitableBoolean particularly useful since it allows you to execute a Runnable within the lock whenever a particular state change occurs.