2009-11-21 4 views
16

Ich verstehe, dass Sammlungen wie die Hashtable synchronisiert sind, aber kann mir jemand erklären, wie es funktioniert, und zu welchem ​​Zeitpunkt (s) ist der Zugriff auf gleichzeitige Anrufe beschränkt? Zum Beispiel, sagen wir mal ich einige Iteratoren wie folgt verwenden:Erläutern Sie die Synchronisierung von Sammlungen, wenn Iteratoren verwendet werden?

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>(); 
} 

Kann jemand bitte erklären, ob es irgendwelche Gefahren bei mir sind diese Funktionen zufällig aus verschiedenen Threads aufrufen? Wie macht der Iterator insbesondere seine Synchronisation, besonders wenn er mit entrySet() arbeitet, was auch eine Synchronisation zu erfordern scheint? Was passiert, wenn während einer der Schleifen clear() aufgerufen wird? Was passiert, wenn removeomething() ein Element entfernt, das noch nicht von einer gleichzeitigen Schleife in dosomething1() verarbeitet wurde?

Danke für jede Hilfe!

Antwort

34

Iteration über Sammlungen in Java ist nicht Thread-sicher, auch wenn Sie eine des synchronisierten Wrapper verwenden (Collections.synchronizedMap(...)):

Es ist zwingend notwendig, dass der Benutzer manuell auf die zurück Karte synchronisieren, wenn sie über Iterieren eine seiner Sammlung Ansichten:

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

Andere Anrufe zu synchronisierten Sammlungen sind sicher, da die Wrapper-Klassen sie mit synchronized Blöcken umgeben, die die Wrapper-Sammlung als Monitor verwenden:

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

mit collection die ursprüngliche Kollektion zu sein. Dies funktioniert für alle Methoden, die von einer Sammlung/Map offen gelegt werden, mit Ausnahme des Iterationskrams.

Der Schlüsselsatz einer Karte wird auf die gleiche Weise synchronisiert: Der synchronisierte Wrapper gibt den ursprünglichen Schlüsselsatz überhaupt nicht zurück. Stattdessen wird ein spezieller synchronisierter Wrapper des ursprünglichen Schlüsselsatzes der Sammlung zurückgegeben. Gleiches gilt für den Eintragssatz und den eingestellten Wert.

+0

Die Antwort wurde korrigiert: Der verwendete Monitor ist eigentlich die Wrapper-Sammlung, nicht die ursprüngliche. – Dirk

+0

Das ist sehr hilfreich und sehr gut präsentiert. Ich hatte Probleme, eine Quelle zu finden, die das klar erklärt, also vielen Dank! – DivideByHero

+0

"Iteration über Sammlungen in Java ist nicht threadsicher, auch wenn Sie einen der synchronisierten Wrapper verwenden" O_o terrible – rkarajan

Verwandte Themen