我在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/