在实践中的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

08-18 15:39