Java:使用ConcurrentHashMap作为锁管理器
我正在编写高度并发的应用程序,需要访问大量细粒度的共享资源。 我目前正在写一个全球锁经理来组织这个。 我想知道是否可以搭载标准的ConcurrentHashMap
并使用它来处理锁定? 我正在考虑像下面这样的系统:
ConcurrentHashMap
对象包含资源的唯一字符串id与使用该资源保护资源唯一标识的锁之间的映射 replace(K key, V oldValue, V newValue)
方法获取锁 这个设置是否有重大问题? 表演将如何?
我知道这可能会比写得很好的锁定系统慢得多,但是我更愿意花几天的时间写自己的,尤其是考虑到我可能无法与Java的专业匹配实现地图的并发代码。
另外,我从来没有在高负载情况下使用ConcurrentHashMap,所以我对以下内容感兴趣:
编辑:感谢Holger指出,HashMaps不应该有缩放问题
另外,那里是否有更好/更标准的方法? 我无法找到任何使用这种系统的地方,所以我猜测要么我没有看到一个重大缺陷,要么是其他的东西。
编辑:
我正在编写的应用程序是一个网络服务,处理可变数量的请求。 我正在使用Grizzly项目来平衡多个线程之间的请求。 每个请求使用少量的共享资源(〜30),所以一般情况下,我不会期待大量的争用。 这些请求通常在500毫秒内完成资源处理。 因此,如果请求不是非常时间敏感并且争用应该最小化,那么我会适当地进行阻塞/连续轮询。
一般来说,看到一个合适的解决方案与ConcurrentHashMap
如何在幕后工作非常相似,我想知道我是否可以安全地将它用作快捷方式而不是编写/调试/测试我自己的版本。
重新调整大小的问题是不相关的,因为您已经告诉您对问题中元素数量的估计。 所以你可以给一个ConcurrentHashMap
一个足够大的初始容量来避免任何重新哈希。
性能不取决于元素的数量,这是哈希的主要目标,而是并发线程的数量。
主要问题是您没有如何处理失败的锁的计划。 除非要在锁定成功(不推荐)之前进行轮询,否则需要将线程置于睡眠状态,这意味着当前拥有该锁的线程必须在释放时唤醒睡眠线程(如果存在的话)。 所以你最终需要一个ConcurrentHashMap
不提供的传统Lock
特性。
为每个元素创建一个Lock
(正如你所说的〜1,000,000)不会是一个解决方案。
一个解决方案看起来有点像ConcurrentHashMap
在内部工作。 给定一定的并发级别,即可能拥有的线程数(向上取整),可以创建该数量的Lock
(这将是远远小于1,000,000的数)。
现在您为每个元素分配一个Lock
。 假设它是稳定的,一个简单的赋值将基于该元素的hashCode
。 然后,锁定一个元素意味着锁定指定的Lock
,如果所有当前锁定的元素都映射到不同的Lock
则Lock
将使您达到配置的并发级别。
这可能意味着,如果元素映射到同一个Lock
,但锁定不同元素的线程彼此阻塞,但具有可预测的可能性。 您可以尝试微调并发级别(如上所述,使用比线程数量更高的数字)以找到最佳的折衷方案。
这种方法的一个很大的优点是你不需要维护一个依赖于元素数量的数据结构。 Afaik,新的并行ClassLoader
使用了类似的技术。