[英]Why does ConcurrentHashMap.computeIfAbsent() increment the counter for an already present key?
Running this example code (from Cay Horstmann)运行此示例代码(来自 Cay Horstmann)
ConcurrentHashMap<String,LongAdder> counts = new ConcurrentHashMap<>();
for (String key : "Row, row, row a boat".split("\\PL+"))
counts.computeIfAbsent(key, k -> new LongAdder()).increment();
System.out.println(counts);
The output is输出是
{a=1, Row=1, row=2, boat=1}
I am surprised to see row=2
because I expected computeIfAbsent() would increment only when it found the first "row" and not the second one.看到
row=2
我很惊讶,因为我预计 computeIfAbsent() 只会在它找到第一个“行”而不是第二个“行”时增加。
counts.computeIfAbsent(key, k -> new LongAdder())
This entire expression can go one of two ways:整个表达式可以采用以下两种方式之一:
key
is already in the counts
map. key
已经在counts
映射中。 In this case, the 'computer' function ( k -> new LongAdder()
) is completely ignored;在这种情况下,“计算机”函数(
k -> new LongAdder()
)被完全忽略; it isn't run at all.它根本没有运行。 Instead, the value associated with that key is returned.
而是返回与该键关联的值。
key
is not in the counts
map. key
不在counts
映射中。 In this case, the 'computer' function is executed once, and the value it returns is now associated with the key.在这种情况下,“计算机”函数执行一次,它返回的值现在与键相关联。
In other words, it's identical to:换句话说,它等同于:
LongAdder result;
if (counts.containsKey(key)) result = counts.get(key);
else {
result = new LongAdder();
counts.put(key, result);
}
return result;
Which is a mouthful, potentially less efficient, and potentially non-atomic whereas .computerIfAbsent
can be atomic if you use the right implementation (such as ConcurrentHashMap
).如果您使用正确的实现(例如
ConcurrentHashMap
),这是一个拗口的,可能效率较低且可能不是原子的,而.computerIfAbsent
可以是原子的。
Here's the clue: You then invoke .increment()
on this result, regardless of whether we're in the #1 case or the #2 case .线索如下:然后你调用
.increment()
这个结果,不管我们是在#1 case 还是#2 case 。
In other words:换句话说:
First 'row' is seen, computeIfAbsent
ends up executing the lambda and thus, runs something like counts.put(k, new LongAdder())
and THEN you call .increment()
on this.看到第一个“行”,
computeIfAbsent
最终执行 lambda,因此运行类似counts.put(k, new LongAdder())
的东西,然后你调用.increment()
。
Next, the second 'row' is seen, computeIfAbsent
ends up being equivalent to counts.get(key)
, and you call .increment()
on that.接下来,看到第二个“行”,
computeIfAbsent
最终等同于counts.get(key)
,然后您调用.increment()
。 Which is the same LongAdder we made when we saw the first 'row', and thus this is the second time you are invoking increment()
on it.这与我们看到第一行时制作的 LongAdder 相同,因此这是您第二次在其上调用
increment()
。
It's not computeIfAbsent
that's incrementing anything.增加任何东西的不是
computeIfAbsent
。 It's the .increment()
that increments something.是
.increment()
增加一些东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.