gpt4 book ai didi

java - 最小化 JDK8 ConcurrentHashMap 检查和设置操作的锁定范围

转载 作者:行者123 更新时间:2023-11-30 08:02:48 26 4
gpt4 key购买 nike

1.

我有多个线程更新一个 ConcurrentHashMap。每个线程根据键将一个整数列表附加到映射条目的值。任何线程都没有移除操作。

这里的重点是我想尽可能的减少锁和同步的范围。

我看到 computeIf...() 方法的文档说“当计算正在进行时,其他线程在此 map 上尝试的一些更新操作可能会被阻止”,这不是那么令人鼓舞。另一方面,当我查看它的源代码时,我没有观察到它在整个 map 上锁定/同步的位置。

因此,我想知道使用 computeIf...() 和以下本土“方法 2”的理论性能比较

2.

另外,我觉得我在这里描述的问题可能是您可以在 ConcurrentHashMap 上执行的最简化的 check-n-set(或通常是“复合”)操作之一

但我不是很自信,而且找不到很多指南关于如何在 ConcurrentHashMap 上执行这种简单的复合操作,没有在整个 map 上进行锁定/同步

因此,我们将不胜感激任何对此的一般性良好做法建议。

public void myConcurrentHashMapTest1() {

ConcurrentHashMap<String, List<Integer>> myMap = new ConcurrentHashMap<String, List<Integer>>();

// MAP KEY: a Word found by a thread on a page of a book
String myKey = "word1";

// -- Method 1:
// Step 1.1 first, try to use computeIfPresent(). doc says it may lock the
// entire myMap.
myMap.computeIfPresent(myKey, (key,val) -> val.addAll(getMyVals()));
// Step 1.2 then use computeIfAbsent(). Again, doc says it may lock the
// entire myMap.
myMap.computeIfAbsent(myKey, key -> getMyVals());
}

public void myConcurrentHashMapTest2() {
// -- Method 2: home-grown lock splitting (kind of). Will it theoretically
// perform better?

// Step 2.1: TRY to directly put an empty list for the key
// This may have no effect if the key is already present in the map
List<Integer> myEmptyList = new ArrayList<Integer>();
myMap.putIfAbsent(myKey, myEmptyList);

// Step 2.2: By now, we should have the key present in the map
// ASSUMPTION: no thread does removal
List<Integer> listInMap = myMap.get(myKey);

// Step 2.3: Synchronize on that list, append all the values
synchronized(listInMap){
listInMap.addAll(getMyVals());
}

}

public List<Integer> getMyVals(){
// MAP VALUE: e.g. Page Indices where word is found (by a thread)
List<Integer> myValList = new ArrayList<Integer>();
myValList.add(1);
myValList.add(2);

return myValList;
}

最佳答案

您的假设(按预期使用 ConcurrentHashMap 对您来说太慢)是基于对 Javadoc 的误解。 Javadoc 没有声明整个 map 将被锁定。它也没有说明每个 computeIfAbsent() 操作都执行悲观锁定。

实际上可以锁定的是一个容器(也称为桶),它对应于 ConcurrentHashMap 的内部数组支持中的单个元素。请注意,这不是 Java 7 的包含多个桶的映射段。当这样的 bin 被锁定时,可能被阻止的操作只是更新散列到同一 bin 的 key 。

另一方面,您的解决方案并不意味着避免 ConcurrentHashMap 中的所有内部锁定 - computeIfAbsent() 只是可以降级为的方法之一在更新时使用 synchronized block 。即使是 putIfAbsent() ,您最初使用它为某个键放置一个空列表,如果它没有命中空 bin,也会阻塞。

但更糟糕的是,您的解决方案不能保证您的同步 批量更新的可见性。您可以保证 get() happens-before putIfAbsent() 它观察到的值,但是没有 happens-before 在您的批量更新和随后的 get() 之间。

附言您可以在其 OpenJDK 实现中进一步了解 ConcurrentHashMap 中的锁定:http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/concurrent/ConcurrentHashMap.java , 第 313-352 行。

关于java - 最小化 JDK8 ConcurrentHashMap 检查和设置操作的锁定范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36634094/

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