[英]Java: Using ConcurrentHashMap as a lock manager
I'm writing a highly concurrent application, needing access to a large fine-grained set of shared resources. 我正在编写一个高度并发的应用程序,需要访问一大组细粒度的共享资源。 I'm currently writing a global lock manager to organize this.
我目前正在编写一个全局锁管理器来组织此操作。 I'm wondering if I can piggyback off the standard
ConcurrentHashMap
and use that to handle the locking? 我想知道是否可以附带标准
ConcurrentHashMap
并使用它来处理锁定? I'm thinking of a system like the following: 我在考虑以下系统:
ConcurrentHashMap
object contains a mapping between the unique string id of the resource, and a ConcurrentHashMap
对象包含资源的唯一字符串ID与 replace(K key, V oldValue, V newValue)
method in the hashmap replace(K key, V oldValue, V newValue)
方法获取锁。 Are there any major issues with the setup? 设置是否存在重大问题? How will the performance be?
表现如何?
I know this is probably going to be much slower and more memory-heavy than a properly written locking system, but I'd rather not spend days trying to write my own, especially given that I probably won't be able to match Java's professionally-written concurrency code implementing the map. 我知道这可能会比正确编写的锁定系统要慢得多,而且会占用更多的内存,但是我宁愿不花几天时间尝试编写自己的锁定系统,尤其是考虑到我可能无法与Java专业人士相提并论并发代码实现地图。
Also, I've never used ConcurrentHashMap in a high-load situation, so I'm interested in the following: 另外,我从未在高负载情况下使用ConcurrentHashMap,因此我对以下内容感兴趣:
Edit: Thanks Holger for pointing out that HashMaps shouldn't have that big of an issue with scaling 编辑:感谢Holger指出HashMaps在缩放方面不应该有那么大的问题
Also, is there is a better/more standard method out there? 另外,有没有更好/更标准的方法呢? I can't find any places where a system like this is used, so I'm guessing that either I'm not seeing a major flaw, or theres something else.
我找不到使用这种系统的任何地方,所以我猜我可能没有发现重大缺陷,或者还有其他问题。
Edit: 编辑:
The application I'm writing is a network service, handling a variable number of requests. 我正在编写的应用程序是一个网络服务,处理可变数量的请求。 I'm using the Grizzly project to balance the requests among multiple threads.
我正在使用Grizzly项目在多个线程之间平衡请求。 Each request uses a small number of the shared resources (~30), so in general, I do not expect a large great deal of contention.
每个请求都使用少量的共享资源(约30个),因此,一般而言,我不希望有太多争用。 The requests usually finish working with the resources in under 500ms.
这些请求通常在500毫秒内完成使用资源的工作。 Thus, I'd be fine with a bit of blocking/continuous polling, as the requests aren't extremely time-sensitive and contention should be minimal.
因此,我对一些阻塞/连续轮询没什么问题,因为请求不是非常时间敏感的,因此争用应该最少。
In general, seeing that a proper solution would be quite similar to how ConcurrentHashMap
works behind the scenes, I'm wondering if I can safely use that as a shortcut instead of writing/debugging/testing my own version. 通常,看到合适的解决方案与
ConcurrentHashMap
在后台工作的方式非常相似,我想知道是否可以安全地将其用作快捷方式,而不是编写/调试/测试自己的版本。
The re-sizing issue is not relevant as you already told an estimate of the number of elements in your question. 调整大小的问题无关紧要,因为您已经对问题中的元素数量进行了估算。 So you can give a
ConcurrentHashMap
an initial capacity large enough to avoid any rehashing. 因此,您可以为
ConcurrentHashMap
提供足够大的初始容量,以避免任何重新哈希。
The performance will not depend on the number of elements, that's the main goal of hashing, but the number of concurrent threads. 性能不会取决于元素的数量,这是哈希的主要目标,而是并发线程的数量。
The main problem is that you don't have a plan of how to handle failed locks. 主要问题是您没有如何处理失败的锁的计划。 Unless you want to poll until locking succeeds (which is not recommended) you need a way of putting a thread to sleep which implies that the thread currently owning the lock has to wake up a sleeping thread on release if one exists.
除非要轮询直到锁定成功(不建议这样做),否则您需要一种使线程进入睡眠状态的方法,这意味着当前拥有锁的线程必须在释放线程时唤醒睡眠线程(如果存在)。 So you end up requiring conventional
Lock
features a ConcurrentHashMap
does not offer. 因此,您最终需要使用
ConcurrentHashMap
不提供的常规Lock
功能。
Creating a Lock
per element (as you said ~1,000,000) would not be a solution. 为每个元素创建一个
Lock
(如您所说的〜1,000,000)不是解决方案。
A solution would look a bit like the ConcurrentHashMap
works internally. 解决方案看起来有点像
ConcurrentHashMap
在内部工作。 Given a certain concurrency level, ie the number of threads you might have (rounded up), you create that number of Lock
s (which would be a far smaller number than 1,000,000). 给定一定的并发级别,即您可能具有的线程数量(向上舍入),则创建该数量的
Lock
(比1,000,000小得多)。
Now you assign each element one of the Lock
s. 现在,您为每个元素分配一个
Lock
。 A simple assignment would be based on the element's hashCode
, assuming it is stable. 假设它是稳定的,则将基于该元素的
hashCode
进行简单分配。 Then locking an element means locking the assigned Lock
which gives you up to the configured concurrency level if all currently locked elements are mapped to different Lock
s. 然后锁定元素意味着锁定分配的
Lock
,如果所有当前锁定的元素都映射到不同的Lock
则Lock
可以使您达到配置的并发级别。
This might imply that threads locking different elements block each other if the elements are mapped to the same Lock
, but with a predictable likelihood. 这可能意味着,如果将不同元素锁定到相同的
Lock
,则锁定不同元素的线程会互相阻塞,但是可能性是可预测的。 You can try fine-tuning the concurrency level (as said, use a number higher than the number of threads) to find the best trade-off. 您可以尝试微调并发级别(如前所述,使用比线程数高的数字)来找到最佳的权衡。
A big advantage of this approach is that you do not need to maintain a data structure that depends on the number of elements. 这种方法的一大优势是您不需要维护依赖于元素数量的数据结构。 Afaik, the new parallel
ClassLoader
uses a similar technique. Afaik,新的并行
ClassLoader
使用了类似的技术。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.