J'ai lu plusieurs questions similaires à celle-ci, mais aucune des réponses ne fournit d'idées sur la façon de nettoyer la mémoire tout en conservant l'intégrité du verrou. J'estime que le nombre de paires valeur/clé à un moment donné est de dizaines de milliers, mais le nombre de paires valeur/clé sur la durée de vie de la structure de données est pratiquement infini (en réalité, il ne serait probablement pas plus plus d'un milliard, mais je code dans le pire des cas).verrouillage sur une clé de cache
J'ai une interface:
public interface KeyLock<K extends Comparable<? super K>> {
public void lock(K key);
public void unock(K key);
}
avec une implémentation par défaut:
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();
}
}
Cela fonctionne bien, mais la carte ne fait jamais nettoyé. Ce que j'ai à ce jour pour une mise en œuvre est propre:
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();
}
}
}
Cela fonctionne pour deux fils l'accès à une seule serrure à clé, mais une fois un troisième fil est introduit l'intégrité de verrouillage n'est plus garantie. Des idées?
Ignorer la AddReference superflu() appelle dans le procédé de verrouillage. J'essayais quelques idées et j'ai oublié de les sortir en postant le code ici. – user453385