Java:使用ConcurrentHashMap作为锁管理器

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

  • 单个全局ConcurrentHashMap对象包含资源的唯一字符串id与使用该资源保护资源唯一标识的锁之间的映射
  • 调整并发因子以反映对高水平并发性的需求
  • 使用哈希映射中的原子条件replace(K key, V oldValue, V newValue)方法获取锁
  • 要在锁定多个资源时防止锁争用,必须按字母顺序获取锁
  • 这个设置是否有重大问题? 表演将如何?

    我知道这可能会比写得很好的锁定系统慢得多,但是我更愿意花几天的时间写自己的,尤其是考虑到我可能无法与Java的专业匹配实现地图的并发代码。

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

  • 这将如何扩展到大量元素? (我看着〜1,000,000是一个很好的上限,如果我超出了这个范围,我会愿意更有效地重写)
  • 该文件指出,调整大小“相对”缓慢。 它有多慢? 我可能不得不每分钟左右重新调整一次地图的大小。 这对于我看的地图大小会有问题吗?
  • 编辑:感谢Holger指出,HashMaps不应该有缩放问题

    另外,那里是否有更好/更标准的方法? 我无法找到任何使用这种系统的地方,所以我猜测要么我没有看到一个重大缺陷,要么是其他的东西。


    编辑:

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

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


    重新调整大小的问题是不相关的,因为您已经告诉您对问题中元素数量的估计。 所以你可以给一个ConcurrentHashMap一个足够大的初始容量来避免任何重新哈希。

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

    主要问题是您没有如何处理失败的锁的计划。 除非要在锁定成功(不推荐)之前进行轮询,否则需要将线程置于睡眠状态,这意味着当前拥有该锁的线程必须在释放时唤醒睡眠线程(如果存在的话)。 所以你最终需要一个ConcurrentHashMap不提供的传统Lock特性。

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


    一个解决方案看起来有点像ConcurrentHashMap在内部工作。 给定一定的并发级别,即可能拥有的线程数(向上取整),可以创建该数量的Lock (这将是远远小于1,000,000的数)。

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

    这可能意味着,如果元素映射到同一个Lock ,但锁定不同元素的线程彼此阻塞,但具有可预测的可能性。 您可以尝试微调并发级别(如上所述,使用比线程数量更高的数字)以找到最佳的折衷方案。

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

    链接地址: http://www.djcxy.com/p/91889.html

    上一篇: Java: Using ConcurrentHashMap as a lock manager

    下一篇: Understanding this Clojure code