这可能是一个重复的问题,但是我已经在关于并发的书中找到了这部分代码。据说这是线程安全的:
ConcurrentHashMap<String, Integer> counts = new ...;
private void countThing(String thing) {
while (true) {
Integer currentCount = counts.get(thing);
if (currentCount == null) {
if (counts.putIfAbsent(thing, 1) == null)
break;
} else if (counts.replace(thing, currentCount, currentCount + 1)) {
break;
}
}
}
从我(并发初学者)的角度来看,线程t1和线程t2都可以读取currentCount = 1
。然后,两个线程都可以将地图的值更改为2。如果代码正确,是否有人可以向我解释?
诀窍是replace(K key, V oldValue, V newValue)
为您提供原子性。从文档(重点是我的):
仅当当前映射到给定值时,才替换键的条目。...该操作是原子执行的。
关键字是“原子地”。在其中replace
,“检查旧值是否是我们期望的值,并且只有在需要的时候才将其替换”发生在单个工作块中,没有其他线程能够与它交织。实现需要由它来实现它所需的任何同步,以确保它提供了这种原子性。
因此,不可能两个线程都currentAction == 1
从replace
函数内部看到。其中之一将其视为1,因此对其的调用replace
将返回true。另一个将其视为2(因为第一次调用),因此返回false-并使用新值循环返回以重试currentAction == 2
。
当然,这可能是第三个线程同时将currentAction更新为3,在这种情况下,第二个线程将一直尝试直到幸运的是没有任何人跳到它前面。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句