September 1, 2022September 1, 2022 ConcurrentHashMap 1. ConcurrentHashMap class The ConcurrentHashMap is very similar to the HashMap class, except that ConcurrentHashMap offers internally maintained concurrency. It means we do not need to have synchronized blocks when accessing its key-value pairs in a multithreaded application. //Initialize ConcurrentHashMap instance ConcurrentHashMap<String, Integer> m = new ConcurrentHashMap<>(); //Print all values stored in ConcurrentHashMap instance for each (Entry<String, Integer> e : m.entrySet()) { system.out.println(e.getKey()+"="+e.getValue()); } The above code is reasonably valid in a multi-threaded environment in an application. The reason, I am saying “reasonably valid” is that the above code provides thread safety, but still it can decrease the performance of the application. And ConcurrentHashMap was introduced to improve the performance while ensuring thread safety, right?? 2. The Default Constructor and Arguments To understand that we need to understand the internal working of ConcurrentHashMap class. And the best way to start is to look at the constructor arguments. A fully parametrized constructor of ConcurrentHashMap takes 3 parameters: initialCapacity loadFactor concurrencyLevel The first two arguments are fairly simple as their name implies, but the last one is tricky. The concurrencyLeveldenotes the number of shards. It is used to divide the ConcurrentHashMap internally into this number of partitions, and an equal number of threads are created to maintain thread safety maintained at the shard level. The default value of “concurrencyLevel” is 16. It means 16 shards whenever we create an instance of ConcurrentHashMap using the default constructor, before even adding first key-value pair. It also means the creation of instances for various inner classes like ConcurrentHashMap$Segment, ConcurrentHashMap$HashEntry[] and ReentrantLock$NonfairSync. In most cases, in normal applications, a single shard is able to handle multiple threads with a reasonable count of key-value pairs. And performance will also be optimal. Having multiple shards just makes things complex internally and introduces a lot of unnecessary objects for garbage collection, and all this for no performance improvement. The extra objects created per concurrent hashmap using the default constructor are normally in the ratio of 1 to 50 i.e. for 100 such instances of ConcurrentHashMap, there will be 5000 extra objects created. 3. Recommended Initialization Based on the above analysis, I will suggest using the constructor parameters wisely to reduce the number of unnecessary objects and improve the map’s performance. A good approach can be having initialization like this: ConcurrentHashMap<String, Integer> instance = new ConcurrentHashMap<String, Integer>(16, 0.9f, 1); An initial capacity of 16 ensures a reasonably good number of elements before resizing happens. A load factor of 0.9 ensures a dense packaging inside ConcurrentHashMap which will optimize memory use. And concurrency level set to 1 will ensure that only one shard is created and maintained. Please note that if you are working on a very high concurrent application with a very high frequency of updates in ConcurrentHashMap, you should consider increasing the concurrency level by more than 1, but again it should be a well-calculated number to get the best results. Concurrency concurrencyConcurrentHashMaphashmapthreadthread safety