Monday 18 May 2020

ConcurrentHashMap Concept

CONCURRENTHASHMAP

Hashtable and SynchronizedMap both acquires lock on entire Map object which provides thread-safety, but not good performance as at a time only one thread can access that Map instance.

To overcome this issue, ConcurrentHashMap was introduced in Java 5 along with other concurrent classes like CountDownLatch, CyclicBarrier,  CopyOnWriteArrayList, BlockingQueue within java.util.Concurrent package.

More than one threads can read and write concurrently in ConcurrentHashMap and still it provides thread-safety. Amazing, isn't it? How is it implemented internally?


Well, ConcurrentHashMap divides the Map instance into different segments. And each thread acquires lock on each segment. By default it allows 16 threads to access it simultaneously without any external synchronization i.e. by default concurrency level is 16. We can also increase or decrease the default concurrency level while creating ConcurrentHashMap by using below constructor :

ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)

Concurrency-Level (default value 16): Defines the number which is an estimated number of concurrently updating threads. The implementation performs internal sizing to try to accommodate this  many threads. 

Load-Factor (default value 0.75: It's a threshold, used to control resizing.

Initial Capacity  (default value 16): The implementation performs internal sizing to accommodate these many elements.

When we say, ConcurrentHashMap locks only part of it.It actually locks a Segment. So  if two threads are  writing different segments in same ConcurrentHashMap, it allows write operation without any conflicts.

So Segments are only for write operations. In case of read operation, it allows full concurrency and provides most recently updated value using volatile variables.

 ConcurrentHashMap class declaration

public class ConcurrentHashMap<K,V>  
extends AbstractMap<K,V>  
implements ConcurrentMap<K,V>, Serializable 

 ConcurrentHashMap Constructor : 

ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)

Can Multiple thread write in the same segment?

No. Thread acquires a lock on segment in put() operation and at a time only one thread can write in that segment.

Can two threads write in the different segment?

Yes. Two threads are allowed to write concurrently in different segments.

Can Multiple thread read from the same segment?

Yes. Thread doesn't acquire a lock on segment in get() operation and any number of threads can read from the same segment.

If one thread is writing in a segment, can another thread read from that segment()?

Yes. but in this case last updated value will be seen by the reading thread.

Can ConcurrentHashMap use Null keys and values?

ConcurrentHashMap doesn't allow null keys and null values.

If we choose ConcurrenyLevel as 10 then what will be size of Segment array? Is Segment array size exactly same as concurrenyLevel? If No, then how is the Segment array size calculated?

Segment array size is calculated based on concurrenyLevel specified but it doesn't mean it will be exactly same as concurrenyLevel.

If concurrenyLevel is 10 then Segment array size will be 16.

Segment array size = 2 to the power x, where result should be >= concurrenyLevel(in our case it is 10)
Segment array size = 2 to the power x >= 10

Segment array size = 2 ^ 1 = 2   >= 10 (False)
Segment array size = 2 ^ 2 = 4   >= 10 (False)
Segment array size = 2 ^ 3 = 8   >= 10 (False)
Segment array size = 2 ^ 4 = 16 >= 10 (True)

Segment array size is 16.

Example: 2
concurrenyLevel = 8 then Segment array size = ?
Find 2 ^ x >= 8

2 ^ 1 >= 2
2 ^ 2 >= 4
2 ^ 3 >= 8
Segment array size will be 8.