使用ConcurrentMap.replace點下面是從Java併發摘錄實踐:什麼是在這個例子中
public class DelegatingVehicleTracker {
private final ConcurrentMap<String, Point> locations;
private final Map<String, Point> unmodifiableMap;
public DelegatingVehicleTracker(final Map<String, Point> points) {
this.locations = new ConcurrentHashMap<>(points);
this.unmodifiableMap = Collections.unmodifiableMap(this.locations);
}
public Map<String, Point> getLocations() {
return unmodifiableMap;
}
public Point getLocation(final String id) {
return locations.get(id);
}
public void setLocation(final String id, final int x, final int y) {
if (null == locations.replace(id, new Point(x, y))) {
throw new IllegalArgumentException("Invalid vehicle name: " + id);
}
}
}
我的問題是關於它使用ConcurrentMap.replace
的setLocation
方法。此方法的JavaDoc說它等價於:
if (map.containsKey(key)) {
return map.put(key, value);
} else return null;
除了該操作是以原子方式執行的。
如果我們不使用原子版本,會出現什麼問題。一種可能性是一個線程看到映射包含一個給定的鍵,並且在它爲該鍵放置一個新值之前,另一個線程刪除該鍵 - 值對,但由於示例中的類不允許移除,所以這不會發生。
另一種可能性是兩個線程試圖用不同的值替換相同的密鑰。在這種情況下,一個線程可能不會返回正確的先前值,但在此示例中我們不關心之前的值,方法setLocation
返回void
。
因此,似乎該方法可以被重寫而沒有replace
。這就是我的問題。在書中同一類的後續版本中,與上述版本幾乎相同,方法setLocation
不使用replace
,只是containsKey
,我在想這是否會影響線程安全。