2009-11-21 18 views
16

Capisco che le raccolte come Hashtable siano sincronizzate, ma qualcuno può spiegarmi come funziona come ea che punto l'accesso è limitato alle chiamate simultanee? Per esempio, diciamo che faccio uso di iteratori come questo:Spiega la sincronizzazione delle raccolte quando vengono utilizzati gli iteratori?

Hashtable<Integer,Integer> map = new Hashtable<Integer,Integer>(); 

void dosomething1(){ 
    for (Iterator<Map.Entry<Integer,Integer>> i = map.entrySet().iterator(); i.hasNext();){ 
     // do something 
    } 
} 
void dosomething2(){ 
    for (Iterator<Map.Entry<Integer,Integer>> i = map.entrySet().iterator(); i.hasNext();){ 
     // do something 
     // and remove it 
     i.remove(); 
    } 
} 
void putsomething(int a, int b){ 
    map.put(a,b); 
} 
void removesomething(int a){ 
    map.remove(a); 
} 
var clear(){ 
    map = new Hashtable<Integer,Integer>(); 
} 

Qualcuno può spiegare se ci sono delle insidie ​​con me chiamano queste funzioni a caso da diversi thread? In che modo l'iteratore, in particolare, fa la sua sincronizzazione, specialmente quando usa entrySet(), che sembrerebbe richiedere anche la sincronizzazione? Cosa succede se clear() viene chiamato mentre è in corso uno dei loop? Cosa succede se removesomething() rimuove un oggetto che non è ancora stato elaborato da un ciclo concorrente in dosomething1()?

Grazie per qualsiasi aiuto!

risposta

34

iterazione su collezioni in Java non è thread-safe, anche se si utilizza uno dei wrapper sincronizzati (Collections.synchronizedMap(...)):

E 'indispensabile che l'utente sincronizzare manualmente sulla restituita mappa quando l'iterazione di una qualsiasi delle sue vedute di raccolta:

Map m = Collections.synchronizedMap(new HashMap()); 
... 
Set s = m.keySet(); // Needn't be in synchronized block 
... 
synchronized(m) { // Synchronizing on m, not s! 
    Iterator i = s.iterator(); // Must be in synchronized block 
    while (i.hasNext()) 
     foo(i.next()); 
} 

Java Collection Framework docs

Altre chiamate verso collezioni sincronizzati sono sicuri, le classi involucro li circondano di synchronized blocchi, che utilizzano la raccolta involucro come il loro monitoraggio:

public int size() { 
    synchronized(this) { 
     return collection.size(); 
    } 
} 

con collection essendo collezione originale. Questo funziona per tutti i metodi esposti da una raccolta/mappa, ad eccezione del materiale di iterazione.

Il set di chiavi di una mappa viene sincronizzato allo stesso modo: il wrapper sincronizzato non restituisce affatto il set di chiavi originale. Invece, restituisce uno speciale wrapper sincronizzato dell'insieme di chiavi originale della collezione. Lo stesso vale per il set di voci e il set di valori.

+0

Risolto il problema: il monitor utilizzato è in realtà la collezione di wrapper, non quella originale. – Dirk

+0

Questo è super utile e presentato molto bene. Avevo difficoltà a trovare una fonte che spiegasse chiaramente questo, quindi grazie mille! – DivideByHero

+0

"L'iterazione su raccolte in Java non è thread-safe, anche se si sta utilizzando uno dei wrapper sincronizzati" O_o terrible – rkarajan

Problemi correlati