How does DelegatingVehicleTracker (p. 65 Goetz) return a live view?

On page 65 and 66 of Java Concurrency in practice, Brian Goetz lists the following code:

@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)); } } 

About this class, Goetz writes:

"... the delegating version [code above] returns an unchanged but live view of the vehicleโ€™s location. This means that if stream A calls getLocations () and stream B subsequently changes the location of some of the points, these changes are reflected in the map returned to stream A. "

In what sense will Thread A unmodifiableMap live? I donโ€™t see how changes made by thread B through setLocation () calls will be reflected in Thread A unmodifiableMap. It will only look like this if Thread A built a new instance of DelegatingVehicleTracker. But whether Thread A contained a reference to this class, I do not see how this is possible.

Goetz goes on to say that getLocationsAsStatic () could be called "a constant look at the required fleet." I'm confused. It seems to me that the opposite is true, that the call to getLocationsAsStatic () will really return a โ€œliveโ€ view, and the call to getLocations () is a class that has not been reconstructed, would return a static unchanged view of the car park.

What am I missing here in this example?

Any thoughts or perspectives appreciated!

+5
source share
3 answers

I think your confusion is caused by a misunderstanding of Collections.unmodifiableMap . A direct card mutation returned by Collections.unmodifiableMap is not allowed, however, a support card mutation is completely fine (as long as a support card allows mutation). For instance:

 Map<String,String> map = new HashMap<>(); Map<String, String> unmodifiableMap = Collections.unmodifiableMap(map); map.put("key","value"); for (String key : unmodifiableMap.keySet()) { System.out.println(key); // prints key } 

So, the unmodifiableMap in the DelegatingVehicleTracker example is supported by a mutable locations map (a thread-safe one). setLocation automatically mutates locations , and therefore, changes will be visible to threads containing references to unmodifiableMap , knowing that these threads cannot mutate unmodifiableMap . Readers do not have access to locations , so the mutation will only be done using the DelegatingVehicleTracker and therefore with the name delegation .

+3
source

In what sense will Thread A unmodifiableMap live? I do not see how changes made by Thread B through calls to setLocation () will be reflected in Thread A unmodifiableMap

This is because getLocations() returns an unmodifiable wrapped map of the actual volatile map.

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

Thus, any changes later will be automatically reflected in the original returned map, since both of them ultimately point to the same internal map object.

Goetz goes on to say that getLocationsAsStatic () could be called the "constant representation of the required fleet"

This code

 public Map<String, Point> getLocationsAsStatic() { return Collections.unmodifiableMap( new HashMap<String, Point>(locations)); } 

is static in the sense that future changes to locations not reflected because it returns a new map with a copy of all current key-value pairs.

+1
source

getLocations() will return a read-only map that will display updates after getLocations() .

getLocationsAsStatic() , on the other hand, will return a read-only snapshot (such as a deep copy) of the location map during getLocationsAsStatic() .

To illustrate:

 Map<String, Point> locs = // a map with point A(1,1) in it DelegatingVehicleTracker tracker = DelegatingVehicleTracker(locs); Map<String, Point> snapshot = getLocationsAsStatic(); Map<String, Point> live = getLocations(); Point newB = // a point A(2,2) tracker.setLocation(newB); snapshot.get("A"); // will read A(1,1) live.get("A"); // will read A(2,2) 
0
source

Source: https://habr.com/ru/post/1235251/


All Articles