管理多个锁

我有以下情况:我同时处理具有给定密钥的请求。 只要每个正在进行的密钥都是唯一的,我就可以同时处理任意数量的请求。

我是Java中的并发新手。 必须有一些模式/实用/现有问题,但我无法弄清楚要搜索什么。 希望有人可以指出我正确的方向,或评论我到目前为止。

这个类管理锁:

class LockMap { private Map locks = new HashMap(); void acquireLock(K key) throws InterruptedException { Object lockObj; synchronized (locks) { lockObj = locks.get(key); if (lockObj == null) lockObj = new Object(); locks.put(key, lockObj); } synchronized (lockObj) { lockObj.wait(); } } void releaseLock(K key) { Object lockObj; synchronized (locks) { lockObj = locks.get(key); locks.remove(key); } if (lockObj != null) { synchronized (lockObj) { lockObj.notify(); } } } } 

然后我像这样使用锁管理器:

 // lockMap is instance of LockMap shared across all threads void doSomething(K key) { lockMap.acquireLock(key); try { // something } finally { lockMap.releaseLock(key); } } 

这是正确的方法吗?

这个怎么样:

创建ConcurrentHashMap

ConcurrentMap myMap = new ConcurrentHashMap<>();

doSomething()方法中,使用地图的putIfAbsent()方法向地图添加一个允许的信号量,只有在地图中不存在该键的情况下。

随后在密钥上执行get()以获取该密钥的信号量,然后执行您的操作。 完成后释放信号量。

 void doSomething(K key) { myMap.putIfAbsent(key, new Semaphore(1)); Semaphore s = myMap.get(myKey); s.aquire(); try { // do stuff } finally { s.release(); } } 

这个方案唯一真正的问题是如果你的密钥列表会无限增长,我没有一个良好的无竞争条件的策略来从地图中删除信号量。 (但是如果你知道你会一遍又一遍地重复使用相同的密钥,或者列表会慢慢增长,那么也许这没关系。)

以下解决方案不会锁定LockMap,因此极端并行。 它使用定制的Locks来跟踪可以删除它们的时刻,并处理并发删除/创建。

 class Lock { boolean busy=true; // locked state, a thread is working int waitCount=0; // number of waiting threads /** returns true if lock succeeded */ synchronized boolean tryLock() throws InterruptedException { if (busy) { waitCount++; } else if (waitCount==0){ // such values mean that the lock is deleted return false; } else { busy=true; return true; } for (;;) { wait(); if (!busy) { waitCount--; busy=true; return true; } } } } class LockMap { private ConcurrentHashMap locks = new ConcurrentHashMap<>(); void acquireLock(K key) throws InterruptedException { for (;;) { Lock lockObj = locks.get(key); if (lockObj==null) { Lock myLockObj = new Lock(); lockObj=locks.putIfAbsent(key, myLockObj); if (lockObj==null) { // successfully inserted, and so locked return; } } // lockObj existed, lock it or wait in queue if (lockObj.tryLock()) { return; } } } void releaseLock(K key) { Lock lockObj = locks.get(key); synchronized (lockObj) { lockObj.busy=false; if (lockObj.waitCount==0) { locks.remove(key); } else { lockObj.notify(); } } } }