gpt4 book ai didi

Java Hashmap - 多线程放置

转载 作者:搜寻专家 更新时间:2023-10-31 19:32:08 27 4
gpt4 key购买 nike

我们最近在我的工作中讨论了在我们的多线程环境中是否需要使用 ConcurrentHashMap 或者我们是否可以简单地使用常规 HashMap。 HashMap 的论点有两个:它比 ConcurrentHashMap 更快,所以我们应该尽可能使用它。并且 ConcurrentModificationException 显然只在您迭代 Map 时出现,因为它被修改了,所以“如果我们只从 map 中 PUT 和 GET,那么常规 HashMap 有什么问题?”是论点。

我认为并发的 PUT 操作或并发的 PUT 和 READ 可能会导致异常,所以我整理了一个测试来证明这一点。测试很简单;创建 10 个线程,每个线程一次又一次地将相同的 1000 个键值对写入 map ,持续 5 秒,然后打印生成的 map 。

结果其实很困惑:

Length:1299
Errors recorded: 0

我以为每个键值对在 HashMap 中都是唯一的,但通过映射,我可以找到多个相同的键值对。 我预计会出现某种异常或损坏的键或值,但我没想到会这样。这是怎么发生的?

这是我使用的代码,供引用:

public class ConcurrentErrorTest
{
static final long runtime = 5000;
static final AtomicInteger errCount = new AtomicInteger();
static final int count = 10;

public static void main(String[] args) throws InterruptedException
{
List<Thread> threads = new LinkedList<>();
final Map<String, Integer> map = getMap();

for (int i = 0; i < count; i++)
{
Thread t = getThread(map);
threads.add(t);
t.start();
}

for (int i = 0; i < count; i++)
{
threads.get(i).join(runtime + 1000);
}

for (String s : map.keySet())
{
System.out.println(s + " " + map.get(s));
}
System.out.println("Length:" + map.size());
System.out.println("Errors recorded: " + errCount.get());
}

private static Map<String, Integer> getMap()
{
Map<String, Integer> map = new HashMap<>();
return map;
}

private static Map<String, Integer> getConcMap()
{
Map<String, Integer> map = new ConcurrentHashMap<>();
return map;
}

private static Thread getThread(final Map<String, Integer> map)
{
return new Thread(new Runnable() {
@Override
public void run()
{
long start = System.currentTimeMillis();
long now = start;
while (now - start < runtime)
{
try
{
for (int i = 0; i < 1000; i++)
map.put("i=" + i, i);
now = System.currentTimeMillis();
}
catch (Exception e)
{
System.out.println("P - Error occured: " + e.toString());
errCount.incrementAndGet();
}
}
}
});
}
}

最佳答案

您所面对的似乎是一个 TOCTTOU类(Class)问题。 (是的,这种错误经常发生,它有自己的名字。:))

当您向 map 中插入条目时,至少需要发生以下两件事:

  1. 检查 key 是否已经存在。
  2. 如果检查返回真,则更新现有条目,如果不是,则添加新条目。

如果这两个不是原子发生的(就像它们在正确同步的映射实现中那样),那么几个线程可以得出结论,即 key 在步骤 1 中尚不存在,但是当它们到达步骤时2,那不再是真的了。因此多个线程会愉快地插入一个具有相同键的条目。

请注意,这不是唯一可能发生的问题,根据实现情况和您的可见性运气,您可能会遇到各种不同的意外故障。

关于Java Hashmap - 多线程放置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40805373/

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