gpt4 book ai didi

java - 这种 HashMap 中对象的惰性初始化模式是线程安全的吗?

转载 作者:行者123 更新时间:2023-12-03 21:29:37 26 4
gpt4 key购买 nike

如果可能,我想避免锁定读取。但这“感觉”就像双重检查锁定,即使不涉及部分初始化的成员。

这是一个好的构造吗?

private final Map<String, Stuff> stash = new HashMap<String, Stuff>();

public Stuff getStuff(String name) {

if (stash.containsKey(name))
return stash.get(name);

synchronized(stash) {
if (stash.containsKey(name)) {
return stash.get(name);
}
else {
Stuff stuff = StuffFactory.create(name);
stash.put(name, stuff);
return stuff;
}
}
}

最佳答案

不,这个构造不是线程安全的。

假设线程 writer 正在将一些东西放入 map 中,并且 map 太小,必须调整大小。这是在 synchronized block 内完成的,因此您可能认为自己没问题。

在调整大小时, map 中的任何内容都无法保证。

现在,与此同时,假设线程 reader 为现有元素调用 getStuff。此线程可以直接访问 map ,因为它不会在第一次调用 containsKeyget 时命中 synchronized block 。它会发现 map 处于未定义状态,虽然它只是读取,但它会访问内容未定义的数据。可能的结果包括:

  • getStuff 在不应该返回时返回 null
  • getStuff 返回预期的 Stuff
  • getStuff 返回一些内部对象,在调整大小期间由 HashMap 实现使用。
  • getStuff 返回一些与名称无关的其他 Stuff
  • getStuff 陷入无限循环。

这只是一个显而易见的案例,应该很容易理解。所以不,当有像 ConcurrentHashMap 这样设计良好的类时,不要走捷径。或 Guava 的 MapMaker .

顺便说一句:先调用 containsKey 然后再调用 get 使用相同的 key 是相当低效的。只需调用 get,保存结果并将其与 null 进行比较。您将在 map 中保存一次搜索操作。

关于java - 这种 HashMap 中对象的惰性初始化模式是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7342217/

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