Create and put a map value only if not already present, and get it: thread-safe implementation Create and put a map value only if not already present, and get it: thread-safe implementation multithreading multithreading

Create and put a map value only if not already present, and get it: thread-safe implementation


Use ConcurrentHashMap and the lazy init pattern which you used

public static B putIfNeededAndGet(A key) {    B value = map.get(key);    if (value == null) {        value = buildB(...);        B oldValue = map.putIfAbsent(key, value);        if (oldValue != null) {             value = oldValue;        }    }    return value;}


This might not be the answer you're looking for, but use the Guava CacheBuilder, it already does all that and more:

private static final LoadingCache<A, B> CACHE = CacheBuilder.newBuilder()   .maximumSize(100) // if necessary   .build(       new CacheLoader<A, B>() {         public B load(A key) {           return buildB(key);         }       });

You can also easily add timed expiration and other features as well.

This cache will ensure that load() (or in your case buildB) will not be called concurrently with the same key. If one thread is already building a B, then any other caller will just wait for that thread.


In the above solution it is possible that many threads will class processB(...) simultaneously hence all will calculate. But in my case i am using Future and a single thread only get the old value as null hence it will only compute the processB rest will wait on f.get().

 private static final ConcurrentMap<A, Future<B>> map = new ConcurrentHashMap<A, Future<B>>();public static B putIfNeededAndGet(A key) {    while (true) {        Future<V> f = map.get(key);        if (f == null) {            Callable<B> eval = new Callable<V>() {                public B call() throws InterruptedException {                    return buildB(...);                }            };            FutureTask<V> ft = new FutureTask<V>(eval);            f = map.putIfAbsent(arg, ft);            if (f == null) {                f = ft;                ft.run();            }        }        try {            return f.get();        } catch (CancellationException e) {            cache.remove(arg, f);        } catch (ExecutionException e) {        }    }}