Search code examples
javaconcurrencythread-safetyconcurrenthashmap

A project I am working on has a lot of wrapper-classes for ConcurrentHashMap, and uses locks in an (I think) incorrect manner. Is this Correct?


I have to work with a lot of classes that are used to store data in a ConcurrentHashMap and generally look like this:

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.locks.ReentrantLock;

public class Data {
    private ConcurrentHashMap<String, SomeObject> concurrentHashMap = new ConcurrentHashMap<String, SomeObject>();
    private ReentrantLock lock = new ReentrantLock();

    public void add(String string, SomeObject someObject) {
        try {
            lock.lock();
            concurrentHashMap.put(string, someObject);
        }
        finally {
            lock.unlock();
        }
    public void remove(String string) {
        try {
            lock.lock();
            concurrentHashMap.remove(string);
        }
        finally {
            lock.unlock();
        }
    public SomeObject get(String string) {
        try {
            lock.lock();
            return concurrentHashMap.get(string);
        }
        finally {
            lock.unlock();
        } 
    }

Solution

  • is the lock even necessary?

    No, in your case (to add/remove/get a value) you don't need to use lock. ConcurrentHashMap is designed for such operation. But probably you may change your method "add" in the following manner:

        public SomeObject add(String string, PARAMETERS_TO_CONSTRUCT_SomeObject) {
            SomeObject result = concurrentHashMap.get(string);        
            if (result == null) {
                result = new SomeObject(PARAMETERS_TO_CONSTRUCT_SomeObject);
                SomeObject old = map.putIfAbsent(string, result);
                if (old != null) {
                    result = old;
                }
            }
            return result;
        }
    

    This guaranties you always have only one instance of SomeObject associated with the given key and prevents unnecessary instance creation/memory allocation.

    does it make any sense to make a ConcurrentHashMap volatile?

    I think the best way to publish your ConcurrentHashMap safely in this case is to define it as a final one:

        private final ConcurrentHashMap<String, SomeObject> concurrentHashMap = new ConcurrentHashMap<>();