gpt4 book ai didi

java - 在此示例中使用ConcurrentMap.replace有什么意义?

转载 作者:行者123 更新时间:2023-12-03 12:59:32 26 4
gpt4 key购买 nike

这是Java Concurrency in Practice的摘录:

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);
}
}
}

我的问题是关于使用 setLocationConcurrentMap.replace方法。此方法的JavaDoc表示它等效于:
if (map.containsKey(key)) {
return map.put(key, value);
} else return null;

除了该操作是原子执行的。

如果不使用原子版本,可能会出问题。一种可能是,一个线程看到该映射包含一个给定的键,并且在为该键放置新值之前,另一个线程删除了该键值对,但是由于示例中的类不允许删除,因此不会发生这种情况。

另一种可能性是,两个线程试图用不同的值替换相同的键。在那种情况下,一个线程可能不会返回正确的先前值,但是在该示例中,我们并不关心先前的值,方法 setLocation返回 void

因此,似乎无需 replace即可重写该方法。这就是促使我提出问题的原因。在本书中与该类几乎相同的后续版本中, setLocation方法不使用 replace,而仅使用 containsKey,我想知道这是否会损害线程安全性。

最佳答案

the method setLocation does not use replace, just containsKey and I was wondering if this could compromise thread safety.



确实如此,您已经完美地描述了它

What could go wrong if we don't use the atomic version. One possibility is that one thread sees that the map contains a given key and before it puts a new value for that key, another thread removes that key-value pair, but since the class in the example does not allow removals, this cannot happen.



这就是为什么ConcurrentHashMap.replace的实现锁定它尝试替换的节点的原因
/**
* Implementation for the four public remove/replace methods:
* Replaces node value with v, conditional upon match of cv if
* non-null. If resulting value is null, delete.
*/
final V replaceNode(Object key, V value, Object cv) {
int hash = spread(key.hashCode());
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0 ||
(f = tabAt(tab, i = (n - 1) & hash)) == null)
break;
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
boolean validated = false;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
validated = true;
for (Node<K,V> e = f, pred = null;;) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
V ev = e.val;
if (cv == null || cv == ev ||
(ev != null && cv.equals(ev))) {
oldVal = ev;
if (value != null)
e.val = value;
else if (pred != null)
pred.next = e.next;
else
setTabAt(tab, i, e.next);
}
break;
}
pred = e;
if ((e = e.next) == null)
break;
}
}
else if (f instanceof TreeBin) {
validated = true;
TreeBin<K,V> t = (TreeBin<K,V>)f;
TreeNode<K,V> r, p;
if ((r = t.root) != null &&
(p = r.findTreeNode(hash, key, null)) != null) {
V pv = p.val;
if (cv == null || cv == pv ||
(pv != null && cv.equals(pv))) {
oldVal = pv;
if (value != null)
p.val = value;
else if (t.removeTreeNode(p))
setTabAt(tab, i, untreeify(t.first));
}
}
}
}
}
if (validated) {
if (oldVal != null) {
if (value == null)
addCount(-1L, -1);
return oldVal;
}
break;
}
}
}
return null;
}

关于java - 在此示例中使用ConcurrentMap.replace有什么意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43167073/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com