0
votes

We have a Interface that returns HashMap .

Now due to thread safty we have synchronized our Map using

Collections.synchronizedMap(new HashMap());

Now clients that are using our Interface facing class cast exception since

Collections.synchronizedMap returns a synchronized map and which can not be cast to hash Map

We have to convert this synchronizedMap back to hash map

Is there any way to convert synchronizedMap returned by

Collections.synchronizedMap() back to hash map.

3
They can copy it with new HashMap<>(map), or do they want the original? - Paul Boddington
HashMap<...> map = new HashMap<>(); Create and distribute Collections.synchronizedMap(map); as you wish, then, when you need the unsynchronized version, just use the original map. - aioobe
Not sure it's applicable for your situation, but the bottom line is your interface should return Map, not HashMap. Your situation is exactly the reason why the Map interface exists. - Jiri Tousek
@aioobe That's all sorts of dangerous, since any access to the HashMap won't be ordered with respect to any actions to the synch'd map. Even if the synch'd map is all writes, and the HashMap all reads, it's still a data race. - yshavit
I tried copy but synchronizedMap does not have copy method. I think i need to use putAll Method - Sachin Sachdeva

3 Answers

3
votes

If copying is acceptable (that is, you don't need subsequent writes to the synchronized map to be reflected in the returned map), just use HashMap's constructor that takes a Map input. Make sure to synchronize on the synchronizedMap first, since the copy requires iteration over the map (which must anyways be synchronized).

synchronized (map) {
  return new HashMap<>(map);
}

The synchronized block is not really optional. From the docs:

It is imperative that the user manually synchronize on the returned map when iterating over any of its collection views

1
votes

Not perfect, but perhaps it could work in your case: create a class that extends HashMap, but that internally has a synchronized Map. Then, delegate all method calls to your internal map. On the constructors, create a new HashMap, then synchronize it. Something like this:

public class SynchronizedHashMap<K, V> extends HashMap<K, V> {
    private Map<K, V> internalMap;

    public SynchronizedHashMap(int initialCapacity, float loadFactor) {
        internalMap = Collections.synchronizedMap(new HashMap<>(initialCapacity, loadFactor));
    }

    public SynchronizedHashMap(int initialCapacity) {
        internalMap = Collections.synchronizedMap(new HashMap<>(initialCapacity));
    }

    public SynchronizedHashMap() {
        internalMap = Collections.synchronizedMap(new HashMap<>());
    }

    public SynchronizedHashMap(Map<? extends K, ? extends V> m) {
        internalMap = Collections.synchronizedMap(new HashMap<>(m));
    }

    @Override public int size() {
        return internalMap.size();
    }

    @Override public boolean isEmpty() {
        return internalMap.isEmpty();
    }

    @Override public boolean containsKey(Object o) {
        return internalMap.containsKey(o);
    }
    ...
}

And remember, that's why you should be coding for interfaces, not to concrete implementations. Your interface should return a Map, and your client should consume a Map, without knowledge about which Map it is.

0
votes

Will it be ok :

        Map hashMap = new HashMap();
        Map syncMap = Collections.synchronizedMap(hashMap);
        HashMap m = new HashMap(syncMap);