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
由可变映射locations
( thread-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)