sto usando un WeakHashMap contemporaneamente. Voglio ottenere un blocco a grana fine basato su un parametro Integer; se filo A deve modificare una risorsa identificata da integer a
e filo B fa lo stesso per risorsa identificata da intero b
, allora non devono essere sincronizzati. Tuttavia, se ci sono due thread che utilizzano la stessa risorsa, ad esempio il thread C utilizza anche una risorsa identificata da Integer a
, quindi ovviamente i thread A e C devono essere sincronizzati sullo stesso blocco.Iterazione un WeakHashMap
Quando non ci sono più le discussioni che hanno bisogno la risorsa con ID X poi il blocco nella mappa per key = X possono essere rimossi. Tuttavia, un altro thread può entrare in quel momento e provare a utilizzare il blocco in Map per ID = X, quindi abbiamo bisogno di sincronizzazione globale quando si aggiunge/rimuove il blocco. (Questo sarebbe l'unico posto in cui ogni thread deve essere sincronizzato, indipendentemente dal parametro Integer) Ma, un thread non può sapere quando rimuovere il blocco, perché non sa che è l'ultimo thread che usa il lock.
Ecco perché sto utilizzando un WeakHashMap: quando l'ID non è più utilizzato, la coppia chiave-valore può essere rimossa quando il GC vuole.
Per assicurarsi che ho un forte riferimento alla chiave di una voce già esistente, e proprio questo riferimento a un oggetto che costituisce la chiave della mappatura, ho bisogno di iterare l'keySet della mappa:
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
}
Ora, il contenuto della mappa può cambiare mentre lo itera? Penso di no, perché chiamando mrLocks.keySet()
, ho creato un riferimento forte a tutte le chiavi per l'ambito dell'iterazione. È corretto?
Vedere: http://stackoverflow.com/questions/2861410/weakhashmap-iteration-and-garbage-collection – ikettu
Penso di no, da [JavaDoc] (http://docs.oracle.com/javase/7/ docs/api/java/util/WeakHashMap.html # keySet% 28% 29): "** il set è sostenuta dalla mappa, quindi modifiche alla mappa si riflettono nel set, e viceversa **" * * – m0skit0
@ m0skit0 Ah, potresti avere ragione. Il Set restituito conterrà anche WeakReference ma questo è nascosto proprio come WeakHashMap lo nasconde. Quindi dovrei prima prendere un clone del set di chiavi e poi iterare il clone, suppongo, per assicurarmi di iterare una collezione con riferimenti forti. – Timmos