### ConcurrentHashMap Examples

4 steps when accessing a cache implemented with java.util.ConcurrentHashMap (javadoc):

- get the value from the ConcurrentMap;
- if null, assume it's the first access, and create the value;
- call putIfAbsent on the concurrentMap to store the new value;
- if return value is not null (it's rare but happens), use the return value as the golden copy, and discard the newly-created object.

import java.util.*;To compile and run the SqrtTest (

import java.util.concurrent.*;

public class SqrtTest {

private static final String CONCURRENCY_LEVEL_DEFAULT = "50";

private static final String CONCURRENCY_KEY = "concurrency";

private ConcurrentMap<Double, Double> sqrtCache = new ConcurrentHashMap<Double, Double>();

public static void main(String args[]) {

final SqrtTest test = new SqrtTest();

final int concurrencyLevel = Integer.parseInt(System.getProperty(CONCURRENCY_KEY, CONCURRENCY_LEVEL_DEFAULT));

final ExecutorService executor = Executors.newCachedThreadPool();

try {

for(int i = 0; i < concurrencyLevel; i++) {

for(String s : args) {

final Double d = Double.valueOf(s);

executor.submit(new Runnable() {

@Override public void run() {

System.out.printf("sqrt of %s = %s in thread %s%n",

d, test.getSqrt(d), Thread.currentThread().getName());

}

});

}

}

} finally {

executor.shutdown();

}

}

// 4 steps as outlined above

public double getSqrt(Double d) {

Double sqrt = sqrtCache.get(d);

if(sqrt == null) {

sqrt = Math.sqrt(d);

System.out.printf("calculated sqrt of %s = %s%n", d, sqrt);

Double existing = sqrtCache.putIfAbsent(d, sqrt);

if(existing != null) {

System.out.printf("discard calculated sqrt %s and use the cached sqrt %s", sqrt, existing);

sqrt = existing;

}

}

return sqrt;

}

}

`-Dconcurrency=123`

can be used to adjust the concurrency level):$ javac SqrtTest.javaFrom the above output, we can see at least one calculation is discarded since the value already exists in the cache. It had been added to the cache by another thread between step 1 and step 3.

$ java SqrtTest 0.5 11 999 0.1

calculated sqrt of 0.5 = 0.7071067811865476

sqrt of 0.5 = 0.7071067811865476 in thread pool-1-thread-1

calculated sqrt of 11.0 = 3.3166247903554

sqrt of 11.0 = 3.3166247903554 in thread pool-1-thread-2

calculated sqrt of 999.0 = 31.606961258558215

sqrt of 999.0 = 31.606961258558215 in thread pool-1-thread-1

sqrt of 11.0 = 3.3166247903554 in thread pool-1-thread-2

calculated sqrt of 0.1 = 0.31622776601683794

calculated sqrt of 0.1 = 0.31622776601683794

sqrt of 999.0 = 31.606961258558215 in thread pool-1-thread-1

sqrt of 11.0 = 3.3166247903554 in thread pool-1-thread-8

sqrt of 0.5 = 0.7071067811865476 in thread pool-1-thread-4

sqrt of 0.5 = 0.7071067811865476 in thread pool-1-thread-7 calculated sqrt of 0.1 = 0.31622776601683794

discard calculated sqrt 0.31622776601683794 and use the cached sqrt 0.31622776601683794sqrt of 0.1 = 0.31622776601683794 in thread pool-1-thread-6

...

Multiple input double numbers are used to increase thread contention. When testing with one single input number, I couldn't trigger the race condition as evidenced by the "discard calculated sqrt" log message. It is probably because it takes time for the thread pool to create the second thread, and by the time it kicks in, the result is already calculated by the first thread and well established in the cache.

## 6 comments:

Fantastic example. Its also good to know differences between HashMap and ConcurrentHashMap in Java , which helps to decide when to use CHM

See http://javaopensourcecode.blogspot.com/2012/06/concurrenthashmap.html

Article describes in detail about the internals of HashMap and CocurrentHashMap

Very good article on ConcurrentHashMap. Your readers may be interested in performance of ConcurrentHashMap vs. HashMap as well as thread safety concerns.

Thanks.

P-H

Nice Article. visit more java hashmap examples

Great and Useful Article.

Online Java Training

Java Online Training India

Java Online Course

Java EE course

Java EE training

Best Recommended books for Spring framework

Java Interview Questions

Java Course in Chennai

Java Online Training India

I believe the DISCARD race condition is occurring because of the printf for the calculated sqrt above the exists test. Comment it out and see that there are no longer race conditions (at least for me on my Mac OS). Then replace that printf with a Thread.sleep and increase from 1 ms to 100ms and see the DISCARD race condition error increase along with the time delay.

Post a Comment