gpt4 book ai didi

java - 没有 synchronized 关键字的 ConcurrentHashMap

转载 作者:行者123 更新时间:2023-11-29 07:37:57 24 4
gpt4 key购买 nike

我有一个 ConcurrentHashMap<String,List<String>>由线程访问,线程在附加值之前检查键是否存在。我通过使用 synchronized 得到了这个关键词。如果synchronized未使用关键字则值是错误的。不是 ConcurrentHashMap线程安全?还是这段代码有问题?是否可以在不使用 synchronized 的情况下使此代码正常工作以获得更好的性能?这是执行此操作的代码。

ExecutorService executorService = Executors.newFixedThreadPool(4);
final ConcurrentLinkedQueue<Future<?>> futures = new ConcurrentLinkedQueue<Future<?>>();
final ConcurrentHashMap<String, List<String>> map = new ConcurrentHashMap<String, List<String>>();
final JsonParser parser = new JsonParser();
File[] files = new File(dir).listFiles();
for (final File tfile : files) {
futures.add((Future<String>) executorService.submit(new Runnable() {
public void run() {
Object obj = parser.parse(new FileReader(tfile.getAbsolutePath()));
JsonObject jsonObject = (JsonObject) obj;
String documentname = obj.get("name").toString();
synchronized (map) {
List<String> paths = new ArrayList<String>();
//if key already exists append new path to the value
if (map.containsKey(documentname)) {
paths = map.get(documentname);
}
paths.add(tfile.getAbsolutePath());
map.put(documentname, paths);
}
}
}));
}

最佳答案

你可以尝试替换这个:

String documentname = obj.get("name").toString();
List<String> paths = new ArrayList<String>();
//if key already exists append new path to the value
if (map.containsKey(documentname)) {
paths = map.get(documentname);
}
paths.add(tfile.getAbsolutePath());
map.put(documentname, paths);

用这个:

String documentname = obj.get("name").toString();
List<String> paths = Collections.synchronizedList(new ArrayList<String>());
List<String> existing = map.putIfAbsent(documentname, paths);
if (existing != null) {
paths = existing;
}
paths.add(tfile.getAbsolutePath());

putIfAbsent方法避免了如果两个线程都尝试检查(使用 containsKey)然后将条目放入映射时发生的竞争条件。

synchronizedList方法用同步包装器包装嵌套集合,这样您就不需要同步对嵌套集合的访问。或者,您可以使用 java.util.concurrent 中的并发数据结构。

ThreadSafe是一个发现并发错误的静态分析工具。它可以独立运行,可以在 Eclipse 中运行,也可以用作 SonarQube 插件。特别是,它有一个针对您显示的代码中的两个错误的检查器:

  • get-check-put 的非原子使用(可以用 putIfAbsent 代替)( example report )
  • 并发集合中的共享非线程安全内容 ( example report )

我建议的使用 putIfAbsent 的代码的一个问题是它总是创建一个集合。当映射已经包含给定键的条目时,新集合将被简单地丢弃。但是,这可能对您的应用程序来说效率低下,并且会给垃圾收集器带来额外的压力。

因此,您可能需要考虑这样的事情:

String documentname = obj.get("name").toString();
List<String> paths = map.get(documentname);
if (paths == null) {
paths = Collections.synchronizedList(new ArrayList<String>());
List<String> existing = map.putIfAbsent(documentname, paths);
if (existing != null) {
paths = existing;
}
paths.add(tfile.getAbsolutePath());
}

请注意此 ThreadSafe non-atomic get-check-put 中屏幕左下角的“规则描述”链接。关联。单击“规则描述”链接以进一步解释 get-check-put 问题及其可能的解决方案。

关于java - 没有 synchronized 关键字的 ConcurrentHashMap,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33399075/

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