在实践中的Java并发性的第65和66页上,Brian Goetz列出了以下代码:
@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));
}
}
关于这个课程,Goetz写道:
“...委派版本[上面的代码]返回了不可修改但
车辆位置的“实时”视图。这意味着如果线程A调用
getLocations()和线程B稍后会修改某些
点,这些更改将反映在返回到线程A的映射中。”
从什么意义上说,线程A的unmodifiableMap是“活动的”?我看不到线程B通过调用setLocation()进行的更改如何反映在线程A的unmodifiableMap中。仅当线程A构造了DelegatingVehicleTracker的新实例时,情况才如此。但是,如果线程A持有对该类的引用,我不知道这怎么可能。
Goetz继续说,可以将getLocationsAsStatic()称为“所需舰队的不变视图”。我很困惑。在我看来,情况恰恰相反,如果没有重新构造该类,则对getLocationsAsStatic()的调用确实会返回“实时”视图,而对getLocations()的调用将返回静态的,不变的视图。车队。
在此示例中,我在这里缺少什么?
任何想法或观点表示赞赏!
最佳答案
我认为您的困惑是由于对Collections.unmodifiableMap
的误解。不允许直接使用Collections.unmodifiableMap
返回的图进行突变,但是,对背景图进行突变是完全可以的(只要背景图允许突变)。例如:
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
}
因此,
unmodifiableMap
示例中的DelegatingVehicleTracker
由可变映射locations
(一个thread-safe
一个)支持。 setLocation
通过原子方式对locations
进行更改,因此知道该线程无法对unmodifiableMap
进行更改的更改对于持有引用unmodifiableMap
的线程将可见。读者无权访问
locations
,因此仅通过DelegatingVehicleTracker
即可对其进行更改,因此名称为delegation
。