我有实现任意键的“锁处理程序”的代码。给定一个key
,它确保一次只有一个线程可以调用那个(或等于) process
(这在这里意味着调用externalSystem.process(key)
调用)。
到目前为止,我的代码如下:
public class MyHandler {
private final SomeWorkExecutor someWorkExecutor;
private final ConcurrentHashMap<Key, Lock> lockMap = new ConcurrentHashMap<>();
public void handle(Key key) {
// This can lead to OOM as it creates locks without removing them
Lock keyLock = lockMap.computeIfAbsent(
key, (k) -> new ReentrantLock()
);
keyLock.lock();
try {
someWorkExecutor.process(key);
} finally {
keyLock.unlock();
}
}
}
我知道这段代码可以通向OutOfMemoryError
,因为没有人清楚的地图。
我在思考如何制作地图,它将累积有限数量的元素。当超过限制时,我们应该用新的访问元素替换最旧的访问元素(此代码应该与作为监视器的最旧元素同步)。但是我不知道如何进行回调,它会告诉我超出了限制。
请分享你的想法。
P.S.
我重读了这个任务,现在我发现我有一个限制,handle
方法不能被调用超过8个线程。我不知道它对我有什么帮助,但我只是提到了它。
P.S.2
@Boris给了蜘蛛一个很好的简单的解决方案:
} finally {
lockMap.remove(key);
keyLock.unlock();
}
但是在Boris注意到我们的代码不是线程安全的之后,因为它破坏了行为:
让研究用同样的键调用3个线程:
map.remove(key);
map.remove(key);
。在此之后,thread#3调用方法handle
。它检查map中是否没有这个键的锁,因此它创建新的锁并获取它。因此,对于等于键,可以并行调用thread#2和thread#3。但这不应该被允许。
为了避免这种情况,在映射清除之前,我们应该阻塞任何线程来获取锁,而等待集中的所有线程都没有获取并释放锁。看起来它需要足够复杂的同步,这将导致算法工作缓慢。也许当map大小超过某个限制值时,我们应该不时地清除map。
我浪费了很多时间,但不幸的是,我不知道如何做到这一点。
https://stackoverflow.com/questions/41898355
复制相似问题