当用于计算的函数在同一映射上调用#computeIfAbsent时,我在并发哈希表#computeIfAbsent中遇到了 Activity 锁定条件。
从概念上讲,调用调用如下所示
final Map<String, Boolean> map = new ConcurrentHashMap<>();
map.computeIfAbsent("k1", k1 -> map.computeIfAbsent("k2", k2 -> Boolean.TRUE));
(每次计算之间大约消耗了3毫秒的CPU)。不幸的是,我无法提出良好的单元测试来一致地重现问题。
但是
如果计算功能试图删除对其调用的键,则还有另一个 Activity 锁可能会提供一些线索:
final Map<String, Boolean> map = new ConcurrentHashMap<>();
map.computeIfAbsent("k", k -> map.remove("k"));
尽管第二个示例相当复杂地使用了并发哈希映射,但它导致的堆栈跟踪与第一个 Activity 锁相同,因此可能会有所帮助。
任何帮助将不胜感激!
最佳答案
好了 ConcurrentHashMap.computeIfAbsent
文档明确指出:
在进行计算时,可能会阻止其他线程对该映射进行的某些尝试的更新操作,因此计算应简短而简单,并且不得尝试更新此映射的任何其他映射。
强调我的。内部computeIfAbsent
在包含您的密钥的哈希表条目上同步。当您修改另一个与当前正在处理的条目属于同一条目的键时,您可能具有意外的锁。
通常,您应该避免此类修改。不幸的是,您没有为问题提供足够的上下文,因此我无法提出替代解决方案。