除了HashMap中的整个映射锁之外的每键锁定

时间:2015-02-12 03:43:46

标签: java multithreading scala locking concurrenthashmap

我在Java中有一个大的map = ConcurrentHashMap()而Key,Value是某种Object结构。假设该地图的密钥集是 keySet

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

考虑到这是一张大地图,使用每键锁定可能不是一种可接受的方法。

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)

1 个答案:

答案 0 :(得分:2)

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

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

但是,如果您想要对整个键集进行原子读取 - 修改 - 写入(因此,首先迭代您的键集来计算结果,然后使用该预先计算的结果更改所有这些键)然后&# 39;在ConcurrentHashMap中没有任何工具来提供锁定。

但是,您可以使用番石榴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 }
}

锁定条带化是将锁分配给数据结构的不同区域的概念 - 这里是通过键的hashCode完成的。

你需要非常小心地选择锁定阵列的大小以平衡太少的条纹(你将锁定整个地图并且比单个全局锁更慢)和太多条纹(其中根据K的大小,你会抓住很多锁。

Striped负责以相同的顺序返回锁定以锁定同一组钥匙,以避免餐饮哲学家的问题。