Search code examples
javathread-safetysingletonconcurrenthashmap

Best way to pass a ConcurrentHashMap to another class?


I have a handler class that contains a private ConcurrentHashMap which other classes want, but I'm not sure the best way to give it to them.

My apparent options are..

  1. Return the entire ConcurrentHashMap (sample code below--this sounds dangerous to me, given that CHMs are meant to be used by only one thread at a time)
  2. Create a new HashMap every time you want to return the whole thing.
  3. Return an iterator... but I hate iterators! And it would only be just the keys or the values.
public class StuffHandler {
    private StuffHandler(){}
    public static synchronized StuffHandler getInstance() {
        return INSTANCE;
    }
    private final static ConcurrentHashMap<String, Stuff> myStuff = new ConcurrentHashMap<>();
    public static ConcurrentHashMap<String, Stuff> getStuff() {
        return myStuff;
    }
}

Solution

  • There is no such thing as the best way to pass a ConcurrentHashMap to another class. It all depends on your use case, i.e. on what you want your classes to do.

    You have three options:

    1. Return the map as is:

      return myStuff;
      

      This will let your other classes modify the actual myStuff map and everyone will see the changes. However, there won't be any concurrency issue, since ConcurrentHashMap actually supports concurrent access (hence its name), and it does it in a very efficient way.

    2. Return a copy of the map:

      return new HashMap(myStuff);
      

      This returns a fresh new map to every class that calls your getStuff() method. So every caller can play around with this map, since no one else will see modifications, neither other caller classes nor your StuffHandler class. Keep in mind that if the map is big, it might result expensive to return a copy every time its getter is called.

    3. Return an unmodifiable view of the map:

      return Collections.unmodifiableMap(myStuff);
      

      This does not return a copy of the map. Actually, it doesn't copy anything, but returns a wrapper of your map instead, which doesn't allow modifications. This is transparent to the classes that call getStuff(). This option returns a live view of the map, so the actual myStuff map won't be modified (if a modification over the returned map is attempted, an UnsupportedOperationException will be thrown). Nonetheless, if the actual myStuff map is modified (by some method of your StuffHandler class), every other class that has called getStuff() will see this modification.