2017-09-09 5 views
0

Wenn ich über einen Standard HashMap iteriere und versuche, Elemente hinzuzufügen, während ich iteriere, bekomme ich ConcurrentModificationException.Hinzufügen von Elementen zu einer HashMap gleichzeitig

Also versuche ich, eine HashMap ermöglicht gleichzeitige ergänzt:

ConcurrentHashMap<String, Integer> cMap = new ConcurrentHashMap<>(); 
cMap.put("one", 1); 
cMap.forEach((key, value) -> cMap.put(key + key, value + value)); 
System.out.println(cMap); 

jedoch die resultierende Karte ein bisschen komisch ist:

{oneoneoneoneoneoneoneone=8, one=1, oneone=2, oneoneoneone=4} 

und wenn der Schlüssel zx (cMap.put("zx", 1)) zu ändern, um das Ergebnis jetzt ist:

{zxzx=2, zx=1} 

Fragen:

1) Warum passiert das? Die beiden konkurrierenden Operationen (Iterieren und Hinzufügen) sollten nicht in Konflikt stehen.

2) Wie behebe ich die Inkonsistenz?

Wie entgegengesetzt zu Sammlungen, wenn eine Saite zu ändern, während sie über die Zeichen dieser Zeichenkette Iterieren, wird dieses Problem nicht eingehalten werden:

 String str = scanner.next(); 
     for (int i = 1; i < str.length(); i++) { 
      if (str.charAt(i) == str.charAt(i-1)) { 
       str = str.substring(0, i-1) + str.substring(i+1); 
       i = 0; 
      } 
     } 
     if (str.length() == 0) { 
      System.out.println("Empty String"); 
     } else { 
      System.out.println (str); 
     } 
    } 

zu beachten, dass in der obigen Schleife, ist die Quelle nicht String tatsächlich geändert, aber neu zugewiesen, da String unveränderlich ist und nicht geändert werden kann.

Der obige Code funktioniert gut und konsistent. Ist dies ein Beispiel dafür, warum Strings fadensicher sind?

+1

Ich * wusste *, ich habe das Beispiel [irgendwo] gesehen (https://Stackoverflow.com/a/44307009/2711488) ... – Holger

+0

@Holger Sie wurden auf einer dieser Kommentare zitiert, die Sie dort gemacht (das verursacht ein 'OOM') auf einer lokalen Java-Gruppe, die wir hier manchmal tun :) genial, das wieder zu lesen – Eugene

Antwort

3

Es kommt darauf an, zu welchem ​​Hash-Bucket Ihre neuen Elemente hinzugefügt werden. In Ihrem ersten Beispiel werden Ihre neuen Elemente zu einem späteren Hash-Bucket hinzugefügt als dem, an dem Sie gerade arbeiten, und den der Iterator noch nicht erreicht hat. In Ihrem zweiten Beispiel werden Ihre neuen Elemente zu einem früheren Hash-Bucket hinzugefügt, den der Iterator bereits gelesen hat.

Sie sollten sehr vorsichtig sein, wenn Sie Sammlungen in der Mitte einer Iteration ändern. In Ihrem Fall ist es möglicherweise besser, wenn Sie Ihre neuen Einträge zu einer neuen Karte hinzufügen und diese dann zusammenführen.

+2

Es ist nicht nur" am wahrscheinlichsten ". Sie können tatsächlich die Hash-Bucket-Reihenfolge in der Ausgabe sehen: 'one' wurde zuerst hinzugefügt, Iterator liest es, code fügt' oneone' hinzu, das in einem späteren Bucket endet, Iterator liest es, Code fügt 'oneoneoneone' hinzu, das in einem endet sogar später bucket, Iterator liest es, Code fügt "oneoneoneoneoneoneone" hinzu, was in einem Bucket vor "one" endet, so dass der Iterator endet. Die Standardgröße von Maps bedeutet, dass in diesen kleinen Beispielen kein erneutes Laden stattfindet. – Andreas

Verwandte Themen