Ich verwende eine WeakHashMap gleichzeitig. Ich möchte ein feinkörniges Locking basierend auf einem Integer-Parameter erreichen. Wenn Thread A eine Ressource ändern muss, die von Integer a
identifiziert wird, und Thread B dasselbe für Ressource ausführt, die von Integer b
angegeben wird, müssen sie nicht synchronisiert werden. Wenn es jedoch zwei Threads gibt, die die gleiche Ressource verwenden, sagt Thread C auch eine Ressource, die durch Integer a
identifiziert wird, dann müssen Thread A und C natürlich auf derselben Sperre synchronisieren.Iterieren einer WeakHashMap
Wenn es keine weiteren Threads gibt, die die Ressource mit ID X benötigen, kann die Sperre in der Map für Schlüssel = X entfernt werden. Es kann jedoch ein anderer Thread in diesem Moment kommen und versuchen, die Sperre in der Map für ID = X zu verwenden, sodass wir beim Hinzufügen/Entfernen der Sperre eine globale Synchronisation benötigen. (Dies ist die einzige Stelle, an der jeder Thread unabhängig vom Integer-Parameter synchronisiert werden muss.) Ein Thread kann jedoch nicht wissen, wann er die Sperre entfernen muss, weil er nicht weiß, dass es der letzte Thread ist, der die Sperre verwendet.
Deshalb verwende ich eine WeakHashMap: Wenn die ID nicht mehr verwendet wird, kann das Schlüssel-Wert-Paar entfernt werden, wenn der GC es will.
Um sicherzustellen, dass ich einen starken Bezug auf den Schlüssel eines bereits vorhandenen Eintrag haben, und genau das Objektreferenz, die den Schlüssel der Abbildung bildet, muss ich die keySet der Karte iterieren:
synchronized (mrLocks){
// ... do other stuff
for (Integer entryKey : mrLocks.keySet()) {
if (entryKey.equals(id)) {
key = entryKey;
break;
}
}
// if key==null, no thread has a strong reference to the Integer
// key, so no thread is doing work on resource with id, so we can
// add a mapping (new Integer(id) => new ReentrantLock()) here as
// we are in a synchronized block. We must keep a strong reference
// to the newly created Integer, because otherwise the id-lock mapping
// may already have been removed by the time we start using it, and
// then other threads will not use the same Lock object for this
// resource
}
Kann sich der Inhalt der Map während der Iteration ändern? Ich denke nicht, denn mit dem Aufruf mrLocks.keySet()
habe ich einen starken Verweis auf alle Schlüssel für den Umfang der Iteration erstellt. Ist das korrekt?
Siehe: http://stackoverflow.com/questions/2861410/weakhashmap-iteration-and-garbage-collection – ikettu
Ich denke nicht, von [JavaDoc] (http://docs.oracle.com/javase/7/ docs/api/java/util/WeakHashMap.html # keySet% 28% 29): * "** Das Set wird von der Map unterstützt, sodass Änderungen an der Map im Set widergespiegelt werden und umgekehrt. **" * – m0skit0
@ m0skit0 Ah, du magst Recht haben. Das zurückgegebene Set enthält auch WeakReference, aber das ist versteckt, genau wie WeakHashMap es versteckt. Daher sollte ich zuerst einen Klon des Schlüsselsatzes nehmen und dann den Klon iterieren, um sicherzustellen, dass ich eine Sammlung mit starken Referenzen wiederhole. – Timmos