DelegatingVehicleTracker(第65页Goetz)如何返回“实时”视图?

在Java Concurrency in Practice的第65和66页上,Brian Goetz列出了以下代码:

@ThreadSafe public class DelegatingVehicleTracker { private final ConcurrentMap locations; private final Map unmodifiableMap; public DelegatingVehicleTracker(Map points) { locations = new ConcurrentHashMap(points); unmodifiableMap = Collections.unmodifiableMap(locations); } public Map 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 getLocationsAsStatic() { return Collections.unmodifiableMap( new HashMap(locations)); } } 

关于本课程Goetz写道:

“…委托版本[上面的代码]返回车辆位置的不可修改但”实时“视图。这意味着如果线程A调用getLocations()并且线程B稍后修改某些点的位置,则这些更改反映在返回到线程A的映射中。“

在什么意义上,线程A的不可修改的地图是“活的”? 我没有看到Thread B通过调用setLocation()所做的更改将如何反映在Thread A的unmodifiableMap中。 只有当Thread A构造了DelegatingVehicleTracker的新实例时,情况才会出现。 但是如果线程A持有对这个类的引用,我不知道这是如何可能的。

Goetz继续说getLocationsAsStatic()可以被称为“对所需舰队的不变观点”。 我很迷惑。 在我看来恰恰相反的情况是,对getLocationsAsStatic()的调用确实会返回“实时”视图,并且对getLocations()的调用是不是重新构造的类,会返回静态的,不变的视图车队。

我在这个例子中错过了什么?

任何想法或观点都表示赞赏!

我认为你的困惑是由于对Collections.unmodifiableMap误解。 不允许直接突变Collections.unmodifiableMap返回的映射,但是,改变后备映射是完全正确的(只要支持映射允许突变)。 例如:

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

因此, DelegatingVehicleTracker示例中的unmodifiableMap由可变映射locationsthread-safe映射locations )支持。 setLocation以primefaces方式改变locations ,因此对于持有对unmodifiableMap Map的引用的线程,可以看到更改,因为知道这些线程不能改变unmodifiableMap 。 读者无权访问locations因此只能通过DelegatingVehicleTracker进行变异,因此名称delegation

在什么意义上,线程A的不可修改的地图是“活的”? 我没有看到线程B通过调用setLocation()所做的更改将如何反映在线程A的不可修改的Map中

这是因为getLocations()返回实际可变映射的不可修改的包装映射。

 public DelegatingVehicleTracker(Map points) { locations = new ConcurrentHashMap(points); unmodifiableMap = Collections.unmodifiableMap(locations); } ... public Map getLocations() { return unmodifiableMap; } 

因此,稍后的任何更改都将自动反映在原始返回的地图中,因为它们最终都指向相同的内部Map对象。

Goetz继续说getLocationsAsStatic()可以被称为“对所需舰队的不变观点”

这段代码

 public Map getLocationsAsStatic() { return Collections.unmodifiableMap( new HashMap(locations)); } 

因为它返回一个带有所有当前键值对的副本的新映射,所以未反映未来对locations更改,这是静态的。

getLocations()将返回一个只读映射,该映射将调用getLocations() 之后反映更新。

另一方面, getLocationsAsStatic()在调用getLocationsAsStatic()时返回Location映射的只读快照 (也称为深拷贝)。

为了显示:

 Map locs = // a map with point A(1,1) in it DelegatingVehicleTracker tracker = DelegatingVehicleTracker(locs); Map snapshot = getLocationsAsStatic(); Map 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)