Java ConcurrentHashMap 操作原子性
Java ConcurrentHashMap actions atomicity
这可能是一个重复的问题,但我在一本关于并发的书中找到了这部分代码。这据说是线程安全的:
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)
为您提供了原子性。来自 the docs(强调我的):
Replaces the entry for a key only if currently mapped to a given value. ... the action is performed atomically.
关键字是 "atomically." 在 replace
中,"check if the old value is what we expect, and only if it is, replace it" 作为一个单独的工作块发生,没有其他线程能够与之交错。由实现来执行它需要的任何同步以确保它提供这种原子性。
因此,不可能两个线程都从 replace
函数中看到 currentAction == 1
。其中之一会将其视为 1,因此对 replace
的调用将 return 为真。另一个会将其视为 2(因为第一次调用),因此 return 为 false — 并循环返回重试,这次使用新值 currentAction == 2
.
当然,可能是第三个线程同时将 currentAction 更新为 3,在这种情况下,第二个线程将继续尝试,直到幸运地没有任何人跳到它前面。
使用 put 你也可以替换值。
if (currentCount == null) {
counts.put(thing, 2);
}
Can someone please explain me if the code is okay or not?
除了 yshavit 的回答之外,您还可以使用 compute
中添加的 compute
来避免编写自己的循环 8.
ConcurrentMap<String, Integer> counts = new ...;
private void countThing(String thing) {
counts.compute(thing, (k, prev) -> prev == null ? 1 : 1 + prev);
}
这可能是一个重复的问题,但我在一本关于并发的书中找到了这部分代码。这据说是线程安全的:
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)
为您提供了原子性。来自 the docs(强调我的):
Replaces the entry for a key only if currently mapped to a given value. ... the action is performed atomically.
关键字是 "atomically." 在 replace
中,"check if the old value is what we expect, and only if it is, replace it" 作为一个单独的工作块发生,没有其他线程能够与之交错。由实现来执行它需要的任何同步以确保它提供这种原子性。
因此,不可能两个线程都从 replace
函数中看到 currentAction == 1
。其中之一会将其视为 1,因此对 replace
的调用将 return 为真。另一个会将其视为 2(因为第一次调用),因此 return 为 false — 并循环返回重试,这次使用新值 currentAction == 2
.
当然,可能是第三个线程同时将 currentAction 更新为 3,在这种情况下,第二个线程将继续尝试,直到幸运地没有任何人跳到它前面。
使用 put 你也可以替换值。
if (currentCount == null) {
counts.put(thing, 2);
}
Can someone please explain me if the code is okay or not?
除了 yshavit 的回答之外,您还可以使用 compute
中添加的 compute
来避免编写自己的循环 8.
ConcurrentMap<String, Integer> counts = new ...;
private void countThing(String thing) {
counts.compute(thing, (k, prev) -> prev == null ? 1 : 1 + prev);
}