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