gpt4 book ai didi

Java非最终静态Map在静态 block 中的操作

转载 作者:行者123 更新时间:2023-12-01 17:41:56 24 4
gpt4 key购买 nike

我试图了解下面的代码是否是线程安全的。我在 SO 中遇到了很多问题,但似乎找不到明确的答案。

class Car {
public static Map<String, String> features = new HashMap<>();
static {
features.put("color", "red");
features.put("foo", "bar");
}
public Comparable<?> getValue(String id) {
if(!features.containsKey(id)) {
features.put(id, id);
}
String res = features.get(id);
// some business logic and return stmt.
}
}

我们最近在应用程序中遇到了意外行为,其中 getValue("color") 返回的值为 null。我无法重现这个问题,但似乎是在同时处理两个线程时发生的。

  1. 如果参数在 map 中尚不可用,则仅在 getValue 方法中修改 features map 。
  2. 出现此问题的原因是静态 block 中用于初始化 map 的参数。
  3. 用例示例 - Car c = new Car(); c.getValue("颜色");

任何帮助将不胜感激。谢谢。

最佳答案

不,这不是线程安全的。

来自Javadoc of HashMap :

Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.

因此,同步对 map 的访问:

String res;
synchronized (features) {
if(!features.containsKey(id)) {
features.put(id, id);
}
res = features.get(id);
}

并将字段设置为final,并在静态初始值设定项内进行同步。

或者,更好的是,使用 ConcurrentHashMapcomputeIfAbsent 方法。

String res = concurrentFeatures.computeIfAbsent(id, k -> id);

(HashMap 在 Java 8+ 中也有一个 computeIfAbsent 方法,但您也需要在同步块(synchronized block)中调用它)。

<小时/>

实际上,在 Java 8+ 中执行此操作的更好方法是使用 getOrDefault,假设您实际上不需要保留以前未见过的键/值对:

res = features.getOrDefault(id, id);

这不会改变映射,所以你不必担心这里的线程安全;您只需确保它已安全初始化:

public final static Map<String, String> features;
static {
Map<String, String> f = new HashMap<>();
f.put("color", "red");
f.put("foo", "bar");
features = f;
}

关于Java非最终静态Map在静态 block 中的操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60017096/

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