java - HashMap 中的每键锁而不是整个映射锁

标签 java multithreading scala locking concurrenthashmap

我在Java中有一个大的map=ConcurrentHashMap(),而Key、Value是某种对象结构。假设该映射的键集是keySet

现在我有一个计算过程如下。我的问题是如何通过不使用整个 map 锁定来获得更好的性能。是否有任何选项,例如使用每键锁或使用其他类型的数据结构?

考虑到这是一个很大的 map ,使用每个键锁可能不是一个可接受的方法。

multiThread():
    for(0 to N):
        K = subset(keySet, m) where m is much smaller than keySet.size
        lock(map)
        for(key in K):
            result = func1(map.get(key), result)
        for(key in K):
            map.put(key, func2(map.get(key), result))
        releaseLock(map)

最佳答案

在java 8+ ConcurrentHashMap中作为compute() function它允许您对单个键执行原子读取-修改-写入操作,因此您可以执行以下操作:

map.compute(key, () -> {
    //call func2 to compute new value and return it
});

但是,如果您希望对整个键集进行原子读取-修改-写入(因此,首先您迭代键集以计算结果,然后使用预先计算的结果更改所有这些键),那么就没有ConcurrentHashMap 中提供该锁定的设施。

但是,您可以使用 Guava 的 Striped lock ,像这样:

Striped<Lock> arrayOfLocks = Striped.lock(20);
// ...later on...
K = subset(keySet, m);
Iterable<Lock> toObtain = arrayOfLocks.bulkGet(K);
for (Lock l : toObtain) { lock it }
try {
   //do your modifications - your holding the stripe locks for all the keys
} finally {
   for (Lock l : toObtain) { unlock it }
}

锁 strip 化是将锁分配给数据结构的不同“区域”的概念 - 这里它是通过 key 的 hashCode 完成的。

您需要非常仔细地选择锁定数组的大小,以在太少的 strip (您将锁定整个 map 并且比单个全局锁慢)和太多的 strip (您将锁定整个 map )和太多的 strip 之间进行平衡将抓取很多锁,具体取决于 K 的大小)。

Striped 负责以相同的顺序返回锁,以锁定同一组 key ,从而避免哲学家就餐问题。

关于java - HashMap 中的每键锁而不是整个映射锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28468890/

相关文章:

java - 已编译的 Groovy 类 - GC

java - Spring引导休息 Controller 。返回对象,包括继承属性和异常处理

java - 在 Intellij 中导入 Scala 库时出现问题

scala - 如何在Intellij中打开SBT工具窗口?

java - 无法识别的选项 : --print-module-descriptor

Java画图程序。框架区域鼠标按下的问题

python - Python3队列: When can a blocking wait with no timeout return None?

Java Runnable 具有大量任务 Rainbow Table

c++ - steady_clock 跨线程是单调的吗?

scala - Spark : java. io.FileNotFoundException:copyMerge 中不存在文件