javasynchronizationhashmapconcurrenthashmap

Thread-safe map with null-key capability


I need a multi-threaded Map object to use in my web server's caching, and I need to have null keys.

HashMap allows me to have null keys, but ConcurrentHashMap doesn't. I tried to create a synchronized version of HashMap using Collections.synchronizedMap(new HashMap()) but it doesn't accept null keys either.

Is there any alternative that I can use, without having to implement some way to wrap the null keys?


Solution

  • The Map returned by Collections.synchronizedMap supports all of the features of the Map you give it. If you give it a HashMap, it supports the null key (and also null values, you said "...I need to have "null" key values..." which can be read either way).

    This works as expected, for instance:

    import java.util.*;
    
    public class MapTest
    {
        public static final void main(String[] args)
        {
            Map map;
    
            try
            {
                map = Collections.synchronizedMap(new HashMap());
                map.put("one", "a");
                System.out.println("Size = " + map.size());
                map.put(null, "b");
                System.out.println("Size = " + map.size());
                System.out.println("map.get(null) = " + map.get(null));
            }
            catch (Exception ex)
            {
                System.out.println("Exception: " + ex.getMessage());
                ex.printStackTrace(System.out);
            }
            System.exit(0);
        }
    }
    

    Output:

    Size = 1
    Size = 2
    map.get(null) = b

    A synchronized map has the issue that, well, it's synchronized. If you can work around the need for null keys and values, ConcurrentHashMap would probably be the better option for a server cache. But it "...does not allow null to be used as a key or value."


    Note that you need to manually synchronize the map from synchronizedMap if you want to iterate. From the JavaDoc:

    It is imperative that the user manually synchronize on the returned map when traversing any of its collection views via Iterator, Spliterator or Stream:

    ...

    Failure to follow this advice may result in non-deterministic behavior.

    The map handles it for you on get and such, but not iteration.