【发布时间】:2017-04-02 10:03:44
【问题描述】:
以下是 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,我想知道这是否会危及线程安全。
【问题讨论】:
标签: java multithreading thread-safety concurrenthashmap