2017-02-21 4 views
1

Beim Experimentieren mit HashMap bemerkte ich etwas seltsam.HashMap mit doppelten Schlüsseln

Lief 4 Threads mit jedem versucht (Schlüssel, Wert) mit Tasten von 0 bis 9999 setzen, Wert eine konstante Zeichenfolge. Nachdem alle Threads ausgeführt wurden, hat map.size() einen Wert größer als 10.000 zurückgegeben. Wie ist es passiert? Bedeutet dies, dass die Karte doppelte Schlüssel enthält?

Ich iterierte auf map.entrySet() und festgestellt, dass die Anzahl für einige Schlüssel in der Tat mehr als 1 war. Welcher Wert würde zurückgegeben, wenn ich eine get() auf der Karte für einen solchen Schlüssel.

Hier ist der Code, den ich

versucht
final HashMap<String, String> vals = new HashMap<>(16_383); 
Runnable task = new Runnable() { 
    @Override 
    public void run() { 
     for (int i = 0; i < 10000; i++) { 
      vals.put(""+i, Thread.currentThread().getName()); 
     } 
    } 
}; 
Thread thread = new Thread(task, "a"); 
Thread thread1 = new Thread(task, "b"); 
Thread thread2 = new Thread(task, "c"); 
Thread thread3 = new Thread(task, "d"); 
thread.start(); 
thread1.start(); 
thread2.start(); 
thread3.start(); 
thread.join(); 
thread1.join(); 
thread2.join(); 
thread3.join(); 
System.out.println(Thread.currentThread().getName() + "vals "+ vals.size()); 
System.out.println(Thread.currentThread().getName() + "vals "+ vals.entrySet().size()); 
System.out.println(Thread.currentThread().getName() + "vals "+ vals.keySet().size()); 
+1

HashMap ist nicht threadsicher. – Arqan

+0

"Welchen Wert würde zurückgegeben, wenn ich ..." Warum nicht einfach tun und sehen? –

+0

@DM. Ich denke nicht, dass der Test zwischen Läufen wiederholt werden kann, möglicherweise nicht einmal innerhalb eines gegebenen Laufs. –

Antwort

5

HashMap nicht sicher ist, fädeln, wie ausdrücklich in der verlinkten Dokumente zur Kenntnis genommen. Sie geben ein gutes Beispiel dafür, warum dies so ist. Ja, Sie geben doppelte Schlüssel ein, weil put nicht überprüft, dass ein anderer Thread denselben Schlüssel einfügt. Das bedeutet, dass es nicht threadsicher ist.

Das Abrufverhalten ist nicht definiert, sodass es an diesem Punkt den gewünschten Wert zurückgeben kann. Es ist wahrscheinlich sehr Implementierung, Plattform und sogar Timing-abhängig.

Es gibt einige Problemumgehungen. Die in der Dokumentation vorgeschlagen ist

Map m = Collections.synchronizedMap(new HashMap(...));

Eine weitere Option ist ConcurrentHashMap zu verwenden, die ausdrücklich für den Zweck ausgelegt ist.

Verwandte Themen