1

I got the following code from Goetz's book (Java Concurrency in Practice).

The book says passing ConcurrentMap as a parameter in Collections.unmodifiableMap will give the "live" view of locations (i.e., calling getLocations() below), which means a call of setLocation will reflect to the caller.

But, passing HashMap as a parameter in Collections.unmodifiableMap will give the original view (static view) of locations (i.e., calling getLocationsAsStatic() below)

Would anyone explain the reasons behind? Thank you

@ThreadSafe
public class DelegatingVehicleTracker {
    private final ConcurrentMap<String, Point> locations;
    private final Map<String, Point> unmodifiableMap;

    public DelegatingVehicleTracker(Map<String, Point> points) {
        locations = new ConcurrentHashMap<String, Point>(points);
        unmodifiableMap = Collections.unmodifiableMap(locations);
    }

    public Map<String, Point> getLocations() {
        return unmodifiableMap;
    }

    public Point getLocation(String id) {
        return locations.get(id);
    }

    public void setLocation(String id, int x, int y) {
        if (locations.replace(id, new Point(x, y)) == null)
            throw new IllegalArgumentException("invalid vehicle name: " + id);
    }

    // Alternate version of getLocations (Listing 4.8)
    public Map<String, Point> getLocationsAsStatic() {
        return Collections.unmodifiableMap(
                new HashMap<String, Point>(locations));
    }
}

@Immutable
public class Point {
    public final int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
  • See also https://stackoverflow.com/q/33532745/4288506 which is similar and about the same example from Java Concurrency in Practice – Marcono1234 May 03 '19 at 09:32

1 Answers1

2

The difference in behavior is not due to the different types of maps, but rather how they are created. Collections.unmodifiableMap just wraps the given map.

Your ConcurrentMap<String, Point> locations is the map you are modifying, so when you are wrapping it you will still see up to date values when using the unmodifiable map.

However your HashMap is created using new HashMap<String, Point>(locations). The documentation for this constructor says:

Constructs a new HashMap with the same mappings as the specified Map.

Parameters:
    m - the map whose mappings are to be placed in this map

So it actually copies all of the entries of the given map into the newly created one. Therefore this new map has no relation to the locations map anymore.

Marcono1234
  • 5,856
  • 1
  • 25
  • 43