Kann die Größe einer Java HashMap () nicht mit der tatsächlichen Größe der Einträge übereinstimmen?

7

Ich habe eine Java HashMap namens statusCountMap.
Calling size () ergibt 30.
Aber wenn ich die Einträge manuell zähle, ist es 31 Dies ist in einem meiner TestNG Unit Tests. Die folgenden Ergebnisse stammen aus dem Eclipse-Anzeigefenster (Typcode - & gt; Hervorhebung - & gt; Treffer Anzeigeergebnis der Auswertung des ausgewählten Textes).

%Vor%

Was gibt? Jeder hat das erlebt?
Ich bin mir ziemlich sicher, dass statusCountMap zu diesem Zeitpunkt nicht geändert wird.
Es gibt zwei Methoden (nennen wir sie methodA und methodB), die statusCountMap gleichzeitig ändern, indem Sie incrementCountInMap wiederholt aufrufen.

%Vor%

methodD ist, wo ich das Problem bekomme. methodD hat eine TestNG @ dependsOnMethods = {"methodA", "methodB"}. Wenn also methodD ausgeführt wird, ist statusCountMap bereits ziemlich statisch. Ich erwähne das, weil es ein Fehler in TestNG sein könnte.
Ich benutze Sun JDK 1.6.0_24. TestNG ist testng-5.9-jdk15.jar

Hmmm ... nachdem ich meinen Post erneut gelesen habe, könnte es an der gleichzeitigen Ausführung von außerhalb des synchronisierten Blocks liegen. map.get (key) == null & amp; map.put (Schlüssel, 0), die dieses Problem verursacht?

    
trix 12.03.2011, 15:08
quelle

4 Antworten

11

Ich glaube, Sie können dies erreichen, wenn Sie einen Schlüssel ändern, nachdem er einer HashMap hinzugefügt wurde.

In Ihrem Fall scheint es jedoch nur so zu sein, dass Sie die gleiche Map in zwei Threads ohne korrekte Synchronisation modifizieren. z.B. In Thread A, map.put (Schlüssel, 0), Thread B map.put (Schlüssel2, 0) kann eine Größe von 1 oder 2 ergeben. Wenn Sie das gleiche mit remove tun, können Sie mit einer Größe größer als Sie enden sollte.

    
Peter Lawrey 12.03.2011, 15:14
quelle
4
  

Hmmm ... nachdem ich meinen Post erneut gelesen habe, könnte es an der gleichzeitigen Ausführung von außerhalb des synchronisierten Blocks liegen. map.get (key) == null & amp; map.put (Schlüssel, 0), die dieses Problem verursacht?

Mit einem Wort ... ja.

HashMap ist nicht Thread-sicher. Wenn es also einen Punkt gibt, an dem zwei Threads eine HashMap ohne ordnungsgemäße Synchronisierung aktualisieren könnten, könnte die Map in einen inkonsistenten Zustand geraten. Und selbst wenn einer der Threads nur liest, könnte dieser Thread einen inkonsistenten Zustand für die Karte sehen

Die richtige Methode zum Schreiben dieser Methode lautet:

%Vor%     
Stephen C 12.03.2011 16:05
quelle
4

Wenn Sie die Standard-Anfangskapazität von 16 verwenden und auf diese nicht threadsicher zugreifen, sind Sie auf einen inkonsistenten Zustand vorbereitet. Größe ist ein Statuselement in der Map, das bei der Eingabe jedes Elements aktualisiert wird (Größe ++). Dies liegt daran, dass die Karte selbst ein Array verknüpfter Listen ist und ihre tatsächliche Größe nicht wirklich wiedergeben kann, da sie nicht die Anzahl der darin enthaltenen Elemente angibt. Sobald die Karte einen Prozentsatz (load_factor) der Anfangskapazität erreicht, muss sie sich selbst anpassen, um mehr Objekte aufzunehmen. Wenn ein Rogue-Thread versucht, Elemente hinzuzufügen, während die Größe der Karte geändert wird, weiß wer, in welchem ​​Status sich die Karte befindet.

    
nsfyn55 12.03.2011 17:18
quelle
2

Das Problem, dass der erste map.put (..) nicht synchronisiert ist. Synchronisieren Sie es oder verwenden Sie Collections.synchronizedMap(..) . Testfall:

%Vor%

Einige Ergebnisse, die ich bekomme:

%Vor%     
Thomas Mueller 12.03.2011 16:04
quelle

Tags und Links