After reading so much on ConcurrrentHashMap and how good they are I decided to actually try to compare HashMap with Synchronization and ConcurrentHashMap usage. In this example I have created several threads. One group of these threads are producer and other group is consumer. As you expect producer produces on shared memory and consumer reads it from there. Now important thing to note here is this shared memory.
Shared memory used in this example has 2 different implementation i.e. HashMap and ConcurrentHashMap. Time required to process message is affected by contention caused by several concurrent threads trying to access shared memory. Whatever is the way of synchronizing there will be a place where we need to have memory and execution barriers.
Total time of processing is measured using following variants:
Shared memory Implementation
Number of messages
Threads pool size
Number of contending producer and consumer tasks
Percentage of producer tasks. (How frequently we read compare to we write)
Test:
Main threads starts timer when all threads from threadpool have taken up their tasks (either producer or consumer). Using cyclicbarrier and countdownlatch main thread waits untill all tasks are performed. Once done it takes a note of time. This gives time close to actual time taken to complete given tasks. From this average time to complete one task is calculated.
So this test schedules given number tasks (writerTask + (writerTask * readerFactor)) over thread pool of size 8 to 120. So if there are 5 writers and readerFactor is 20 it indicates that for every writer there are 20 readers. It implies there are total 105 tasks contending for shared memory. This test is repeated for 100 times for same size of thread pool size. Average time taken to complete total tasks for given thread pool size is calculated. Same process is repeated for different thread pool size.
Result of the test:
As you can see from the graph below ConcurrentHashMap's performce is better when contentions are high. Graph shows two lines one for HashMap and other ConcurrentHashMap. Large section of ConcurrentHashmap's red line stays below Hashmap's blue line. This shows that once thread contention goes beyond certain point, CconcurrentHashMap stands out clear winner. There are few odd points like when thread pool size is 8 and 16 concurrenthashmap took more time. However both lines are almost overlapping at the end as thread pool size increased.
Analysis:
As you can see from the graph above red line consistently stays below blue line except couple of thread pool size points. It indicates time taken by CHM is lower than Hashmap. I have repeated this test for different task sizes and observed CHM shows better performance when thread pool size tuned to actual number of contending threads. It gives more visible result when thread pool size is not too small or not too big compared to number of contenders.
Role of JIT compiler
I observed that JIT plays huge role in time taken to complete the tasks. If I run the test keeping every other argument same but just setting -Djava.compiler=NONE vm option, there is significant increase in time taken to complete which expectable. However even with such setting CHM performs better compared to HashMap and difference between the two is even more without JIT than the one with JIT.
Source code of entire test can be downloaded from here:
https://mega.co.nz/#!k0Y2GAIY!MvQ4B17FlrAmfMEeAMRL7mFKa8s6N_1gQOy4U1lkv3U
Please feel free to comment.

No comments:
Post a Comment