我已经阅读了几个与此类似的问题,但没有一个答案提供了如何在保持锁完整性的同时清理内存的想法。我估计在给定时间内键值对的数量为数万,但数据结构生命周期内键值对的数量实际上是无限的(实际上它可能不会更多)超过十亿,但我编码到最坏的情况)。
我有一个界面:
public interface KeyLock<K extends Comparable<? super K>> {
public void lock(K key);
public void unock(K key);
}
使用默认实现:
public class DefaultKeyLock<K extends Comparable<? super K>> implements KeyLock<K> {
private final ConcurrentMap<K, Mutex> lockMap;
public DefaultKeyLock() {
lockMap = new ConcurrentSkipListMap<K, Mutex>();
}
@Override
public void lock(K key) {
Mutex mutex = new Mutex();
Mutex existingMutex = lockMap.putIfAbsent(key, mutex);
if (existingMutex != null) {
mutex = existingMutex;
}
mutex.lock();
}
@Override
public void unock(K key) {
Mutex mutex = lockMap.get(key);
mutex.unlock();
}
}
这很好用,但地图永远不会被清理干净。到目前为止,干净实施的目的是:
public class CleanKeyLock<K extends Comparable<? super K>> implements KeyLock<K> {
private final ConcurrentMap<K, LockWrapper> lockMap;
public CleanKeyLock() {
lockMap = new ConcurrentSkipListMap<K, LockWrapper>();
}
@Override
public void lock(K key) {
LockWrapper wrapper = new LockWrapper(key);
wrapper.addReference();
LockWrapper existingWrapper = lockMap.putIfAbsent(key, wrapper);
if (existingWrapper != null) {
wrapper = existingWrapper;
wrapper.addReference();
}
wrapper.addReference();
wrapper.lock();
}
@Override
public void unock(K key) {
LockWrapper wrapper = lockMap.get(key);
if (wrapper != null) {
wrapper.unlock();
wrapper.removeReference();
}
}
private class LockWrapper {
private final K key;
private final ReentrantLock lock;
private int referenceCount;
public LockWrapper(K key) {
this.key = key;
lock = new ReentrantLock();
referenceCount = 0;
}
public synchronized void addReference() {
lockMap.put(key, this);
referenceCount++;
}
public synchronized void removeReference() {
referenceCount--;
if (referenceCount == 0) {
lockMap.remove(key);
}
}
public void lock() {
lock.lock();
}
public void unlock() {
lock.unlock();
}
}
}
这适用于访问单个密钥锁的两个线程,但是一旦引入第三个线程,就不再保证锁完整性。有什么想法吗?
答案 0 :(得分:0)
我不认为这适用于两个线程。考虑一下:
怎么样:
答案 1 :(得分:0)
我会默认使用固定数组作为条带锁,因为您可以将其调整为您期望的并发级别。虽然可能存在哈希冲突,但好的吊具会解决这个问题。如果锁用于短临界区,那么您可能会在ConcurrentHashMap中创建争用优化的争用。
欢迎您调整我的实现,但我只是为了好玩而实现了动态版本。它在实践中似乎没有用,因此只有固定用于生产。您可以使用ConcurrentHashMap中的hash()函数来提供良好的传播。
ReentrantStripedLock in, http://code.google.com/p/concurrentlinkedhashmap/wiki/IndexableCache