Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do Java's synchronized Collections not use Read/Write locks?

After stuff like Hashtable and Vector where discouraged, and when the Collections synchronized wrappers came up, I thought synchronization would be handled more efficiently. Now that I looked into the code, I'm surprised that it really is just wrapping the collections with synchronization blocks.

Why are ReadWriteLocks not included into, for example, SynchronizedMap in Collections? Is there some efficiency consideration that doesn't make it worth it?

like image 371
Miquel Avatar asked Jul 24 '12 19:07

Miquel


People also ask

Which lock is used for synchronized method?

Locks In Synchronized Methods In this case, the thread acquires the intrinsic lock for the Class object associated with the class.

Why are locks better than synchronized?

Only one thread is allowed to access only one method at any given point of time using a synchronized block. This is a very expensive operation. Locks avoid this by allowing the configuration of various locks for different purpose.

What makes concurrent collections different from synchronized collections?

This is because the Collections. synchronizedMap() requires each thread to acquire a lock on the entire object for both read/write operations. By comparison, the ConcurrentHashMap allows threads to acquire locks on separate segments of the collection, and make modifications at the same time.

Does synchronized block acquire a lock before its execution explain your answer?

Using synchronized means in order for a thread to execute that block or method, it has to acquire a lock referenced (explicitly or implicitly) by that block or method. For the static synchronized methods, that lock is the monitor on the class object.


2 Answers

Read-write locks are part of performance optimization, which means it can allow greater concurrency in certain situations. The necessary condition is, that they are applied on data structures which are read most of the time, but not modified.

Under other conditions they perform slightly worse than exclusive locks, which comes natural since they have a greater complexity.

It is most efficient, if the locks of a read-write lock are held typically for a moderately long time and only few modifications on the guarded resources.

Hence, whether read-write locks are better than exclusive locks depends on the use case. Eventually you have to measure with profiling which locks perform better.

Taking this into account it seems fitting to choose an exclusive lock for Collections.synchronizedMap addressing the general use case instead of the special case with mostly-readers.

Further Links

  • Starvation with ReadWriteLocks
  • Refactoring Java Programs for Flexible Locking

    They wrote a tool which converts locks in a Java application automatically into ReentrantLocks and ReadWriteLocks where appropriate. For measuring purposes they have also provided some interesting benchmarking results:

enter image description here

[...] However, in a configuration where write operations were more prevalent, the version with synchronized blocks was 50% faster than one based on read-write locks with the Sun 1.6.0_07 JVM (14% faster with the Sun 1.5.0_15 JVM).

In a low-contention case with just 1 reader and 1 writer, the performance differences were less extreme, and each of the three types of locks yielded the fastest version on at least one machine/VM configuration (e.g., note that ReentrantLocks were fastest on the 2-core machine with the Sun 1.5.0_15 JVM).

like image 125
Konrad Reiche Avatar answered Oct 23 '22 03:10

Konrad Reiche


I don't think that using ReadWriteLock (if that is what you are talking about) is any faster necessarily than using the synchronized keyword. Both constructs impose locks and erect memory barriers and "happens before" limitations.

You may be talking about doing something smart in Collections.synchronizedMap(...) and friends where read methods are read locked and write methods write locked for performance. That might work fine with the java.util collection classes but could cause synchronization problems with Maps implemented by users if the get() methods were being counted or something -- i.e. where a method that was "read-only" actually made updates to the collection. Yes, doing this would be a terrible idea.

ConcurrentHashmap was written to be high performance and uses volatile fields directly instead of synchronized blocks. This makes the code significantly more complicated as compared to Collections.synchronizedMap(...) but also faster. That is the reason why it is recommended for high performance situations over Collections.synchronizedMap(new HashMap<...>()).

like image 25
Gray Avatar answered Oct 23 '22 04:10

Gray