gpt4 book ai didi

java - 线程安全与否?从并行流更新非线程安全映射

转载 作者:行者123 更新时间:2023-11-30 06:54:45 26 4
gpt4 key购买 nike

下面的代码片段从并行流的 forEach block 更新一个非线程安全的映射(itemsById 不是线程安全的)。

// Update stuff in `itemsById` by iterating over all stuff in newItemsById:
newItemsById.entrySet()
.parallelStream()
.unordered()
.filter(...)
.forEach(entry -> {
itemsById.put(entry.getKey(), entry.getValue()); <-- look
});

对我来说,这看起来不是线程安全的,因为并行流将同时在许多线程中调用 forEach block ,从而调用 itemsById.put(。 .) 同时在多个线程中,itemsById 不是线程安全的。 (但是,我认为使用 ConcurrentMap 代码是安全的)

我写信给一位同事:“请注意,当您插入新数据时,映射可能会分配新内存。这可能不是线程安全的,因为集合不是线程安全的。——无论是否写入不同的来自许多线程的 key ,是线程安全的,依赖于实现,我想。我不会选择依赖它。”

然而他说上面的代码是线程安全的。 -- 是吗?

((请注意:我不认为这个问题过于本地化。实际上现在使用 Java 8 我认为相当多的人会做类似的事情:parallelStream()...foreach(...) 然后对于很多人来说,线程安全问题可能是很好的了解))

最佳答案

你是对的:这段代码不是线程安全的,并且取决于 Map 实现和竞争条件可能会产生任何随机效果:正确的结果、无声的数据丢失、一些异常或无限循环.您可以像这样轻松地检查它:

int equal = 0;
for(int i=0; i<100; i++) {
// create test input map like {0 -> 0, 1 -> 1, 2 -> 2, ...}
Map<Integer, Integer> input = IntStream.range(0, 200).boxed()
.collect(Collectors.toMap(x -> x, x -> x));
Map<Integer, Integer> result = new HashMap<>();
// write it into another HashMap in parallel way without key collisions
input.entrySet().parallelStream().unordered()
.forEach(entry -> result.put(entry.getKey(), entry.getValue()));
if(result.equals(input)) equal++;
}
System.out.println(equal);

在我的机器上,这段代码通常会打印 20 到 40 之间的内容,而不是 100。如果我将 HashMap 更改为 TreeMap,它通常会失败并返回 NullPointerException 或陷入 TreeMap 实现中的无限循环。

关于java - 线程安全与否?从并行流更新非线程安全映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36033134/

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