Java:使用ConcurrentHashMap作为锁管理器

时间:2014-01-17 04:29:03

标签: java multithreading concurrency locking concurrenthashmap

我正在编写高度并发的应用程序,需要访问大量细粒度的共享资源。我正在写一个全球锁定经理来组织这个。我想知道我是否可以背负标准ConcurrentHashMap并使用它来处理锁定?我正在考虑如下系统:

  • 单个全局ConcurrentHashMap对象包含资源的唯一字符串id与使用资源保护线程唯一ID的锁之间的映射
  • 调整并发因子以反映对高并发性的需求
  • 使用hashmap
  • 中的原子条件replace(K key, V oldValue, V newValue)方法获取锁
  • 要在锁定多个资源时防止锁争用,必须按字母顺序获取锁

设置是否有任何重大问题?表现如何?

我知道这可能会比正确编写的锁定系统慢得多且内存更重,但我宁愿不花几天时间来编写自己的锁定系统,特别是考虑到我可能无法匹配Java专业编写的实现地图的并发代码。

另外,我从未在高负载情况下使用ConcurrentHashMap,所以我对以下内容感兴趣:

  • 这对大量元素的扩展程度如何? (我正在考虑~1,000,000是一个好的上限。如果我超越了,我愿意更有效地重写它)
  • 文档指出重新调整大小“相对”缓慢。它有多慢?我可能每分钟都要重新调整一次地图。这对我正在看的地图大小有问题吗?

编辑:感谢Holger指出HashMaps不应该有缩放的大问题

此外,还有更好/更标准的方法吗?我找不到像这样的系统使用的任何地方,所以我猜我要么没有看到一个重大缺陷,要么就是其他东西。


编辑:

我正在编写的应用程序是一个网络服务,处理可变数量的请求。我正在使用Grizzly项目来平衡多个线程之间的请求。 每个请求使用少量的共享资源(~30),所以一般来说,我不期望大量的争用。这些请求通常在500毫秒以内完成资源处理。因此,我可以使用一些阻塞/连续轮询,因为请求不是非常时间敏感的,并且争用应该是最小的。

一般来说,看到一个正确的解决方案与幕后的ConcurrentHashMap工作方式非常相似,我想知道我是否可以安全地将其用作快捷方式,而不是编写/调试/测试我自己的版本

1 个答案:

答案 0 :(得分:1)

重新调整大小的问题并不重要,因为您已经说过了问题中元素数量的估计值。因此,您可以为ConcurrentHashMap提供足够大的初始容量,以避免任何重复。

性能不取决于元素的数量,这是散列的主要目标,而是并发线程的数量。

主要问题是您没有如何处理失败锁的计划。除非你想在锁定成功之前进行轮询(不建议这样做),否则你需要一种将线程置于休眠状态的方法,这意味着当前拥有锁的线程必须在释放时唤醒休眠线程(如果存在)。因此,您最终需要Lock未提供的常规ConcurrentHashMap功能。

每个元素创建一个Lock(正如你所说的那样~1,000,000)不会是一个解决方案。


解决方案看起来有点像ConcurrentHashMap内部工作。给定一定的并发级别,即你可能拥有的线程数(向上舍入),你创建了Lock个数(这个数字远小于1,000,000)。

现在为每个元素分配Lock个。一个简单的赋值将基于元素的hashCode,假设它是稳定的。然后锁定一个元素意味着锁定指定的Lock,如果所有当前锁定的元素都映射到不同的Lock,则会使您达到配置的并发级别。

这可能意味着如果元素映射到相同的Lock,但具有可预测的可能性,则锁定不同元素的线程会相互阻塞。您可以尝试微调并发级别(如上所述,使用高于线程数的数字)来找到最佳权衡。

这种方法的一大优点是您不需要维护依赖于元素数量的数据结构。 Afaik,新的并行ClassLoader使用了类似的技术。