2012-12-18 12 views
7

Ich rufe Funktion, die TreeMap Instanz zurückgibt, und im aufrufenden Code wollte ich die TreeMap ändern. Ich bekomme jedoch eine ConcurrentModificationException.Vermeiden von TreeMap ConcurrentModificationException?

Hier ist mein Code:

public Map<String, String> function1() { 
    Map<String, String> key_values = Collections.synchronizedMap(new TreeMap<String, String>()); 
    // all key_values.put() goes here 

    return key_values; 
} 

Und meine Berufung Code:

Map<String, String> key_values =Collections.synchronizedMap(Classname.function1()); 
//here key_values.put() giving ConcurrentModificationException 
+1

Darf ich den Punkt der Erstellung einer synchronisierten Karte aus Funktion 1 fragen? Es wird von niemandem außer Ihrem "calling code" verwendet ... –

+0

Wie ändert man die Karte? –

Antwort

2

Wenn Sie eine ConcurrentSkipListMap verwenden, kann schneller sein und hat dieses Problem nicht.

public NavigableMap<String, String> function1() { 
    NavigableMap<String, String> key_values = new ConcurrentSkipListMap<String, String>(); 
    // all key_values.put() goes here 

    return key_values; 
} 

Wenn Sie die Schlüssel nicht brauchen können Sie eine ConcurrentHashMap verwenden sortiert werden.

+1

Es kann nützlich sein zu verstehen, was eine * Skip-Liste * ist: https://en.wikipedia.org/wiki/Skip_list –

13

Beachten Sie, dass Collections.synchronizedMap wird nie schützen Sie vor gleichzeitige Änderung, wenn Sie einen Iterator verwenden. Wenn Sie nicht aus mehr als einem Thread auf Ihre Map zugreifen, ist das Erstellen der synchronisierten Karte nutzlos. Lokal begrenzte Sammlungen und Variablen, die nicht an andere Threads übergeben werden, müssen nicht synchronized sein.

Meine Vermutung ist, dass in dem Code, den Sie links aus, bist du über einen von Map.entrySet Iterieren, Map.keySet oder Map.values und putwährend dass Iteration Aufruf (in der for Schleife). Mit dem Code, den Sie gezeigt haben, ist dies die einzige Möglichkeit, dies zu tun.

+0

Ya Sie r schreiben Herr, das war mein Fehler .. Danke –

1

Sie scheinen eine synchronisierte Karte einer synchronisierten Karte zu erhalten. Wenn ich den Anruf zu function1 ersetzen() mit einem seinem Inhalt (vereinfachte) haben wir:

Map<String, String> key_values =Collections.synchronizedMap(Collections.synchronizedMap(new TreeMap<String, String>())); 

Ich denke, Ihre Berufung Linie geändert werden soll:

Map<String, String> key_values = Classname.function1(); 
+1

Nicht wirklich eine Antwort, also keine +1, aber immer noch eine gute Nachricht. – Brian

+0

@Brian Ich denke, dieses Detail ist wichtig. Denn mit diesem doppelten Wrapper wird er nicht in der Lage sein, auf dem TreeMap-Objekt zu synchronisieren, das er benötigt, wenn er versucht, zu aktualisieren und zu aktualisieren. –

1

Sie für ein synchronisiertes MAP suchen Ich nehme an, Sie haben es mit einer Multithread-App zu tun. Wenn Sie in diesem Fall Iterator verwenden möchten, müssen Sie den Block für das MAP synchronisieren.

/*This reference will give error if you update the map after synchronizing values.*/ 
    Map<String, String> values =Collections.synchronizedMap(function1()); 

/*This reference will not give error if you update the map after synchronizing values */ 
     Map<String, String> values = Collections.synchronizedMap(new TreeMap<String, String>()); 


    synchronized (values) 
       {   
        Iterator it = values.entrySet().iterator(); 
        while(it.hasNext()) 
        { 
         it.next() ; 
    // You can update the map here.  
        } 
       } 

Update:

Eigentlich in Ihrem Fall unter Berücksichtigung der err, die Sie zweimal der Karte sind Einwickeln, es in der while-Schleife modifiziert mit einem synchronisierten Block wird ein CM Ausnahme geben, wie Sie es nicht in der Lage sein, auf dem ursprünglichen MAP-Objekt zu synchronisieren, das aktualisiert wird.

Verwandte Themen