Was sind die Unterschiede zwischen einer HashMap
und eine Hashtable
in Java?
Was ist effizienter für Nicht-Thread-Anwendungen?
Es gibt mehrere Unterschiede zwischen HashMap
y Hashtable
in Java:
Hashtable
es synchronisiert in der Erwägung, dass HashMap
nicht ist. Das macht HashMap
besser für Nicht-Thread-Anwendungen, da unsynchronisierte Objekte in der Regel besser funktionieren als synchronisierte.
Hashtable
erlaubt nicht null
Schlüssel oder Werte. HashMap
erlaubt eine null
Taste und eine beliebige Anzahl von null
Werte.
Eine der Unterklassen von HashMap ist LinkedHashMap
Wenn Sie also eine vorhersehbare Iterationsreihenfolge wünschen (die standardmäßig die Einfügereihenfolge ist), können Sie einfach die HashMap
für eine LinkedHashMap
. Dies wäre nicht so einfach, wenn Sie die Hashtable
.
Da die Synchronisierung für Sie kein Problem darstellt, würde ich empfehlen HashMap
. Wenn die Synchronisierung zu einem Problem wird, können Sie sich auch mit ConcurrentHashMap
.
Wenn Sie eine HashMap thread-sicher machen wollen, verwenden Sie Collections.synchronizedMap()
.
Ich möchte auch anmerken, dass der naive Ansatz zur Thread-Sicherheit in Hashtable
("Die Synchronisierung jeder Methode sollte alle Gleichzeitigkeitsprobleme beseitigen!") macht es sehr viel schlechter für Anwendungen mit Gewinde. Sie sind besser dran, wenn Sie eine externe Synchronisierung einer HashMap
(und über die Konsequenzen nachzudenken), oder die Verwendung einer ConcurrentMap
Implementierung (und die Nutzung ihrer erweiterten API für die Gleichzeitigkeit). Fazit: Der einzige Grund für die Verwendung von Hashtable
ist, wenn ein altes API (von ca. 1996) dies erfordert.
HashMap gibt dem Programmierer die Flexibilität, threadSafe Code zu schreiben, wenn er ihn tatsächlich benötigt. Es kam selten vor, dass ich eine thread-sichere Sammlung wie ConcurrentHashMap oder HashTable benötigte. Was ich brauchte, war ein bestimmter Satz von Funktionen oder bestimmte Anweisungen in einem synchronisierten Block, die thread-sicher sein sollten.
Beachten Sie, dass viele der Antworten angeben, dass Hashtable synchronisiert ist. In der Praxis bringt Ihnen das sehr wenig. Die Synchronisierung der Accessor-/Mutator-Methoden verhindert, dass zwei Threads gleichzeitig etwas zur Karte hinzufügen oder daraus entfernen, aber in der realen Welt werden Sie oft zusätzliche Synchronisierung benötigen.
Eine sehr gebräuchliche Redewendung ist "erst prüfen, dann setzen" - d. h. nach einem Eintrag in der Map
und fügen Sie es hinzu, wenn es noch nicht vorhanden ist. Dies ist in keiner Weise ein atomarer Vorgang, egal ob Sie Hashtable
o HashMap
.
Eine gleichwertig synchronisierte HashMap
kann durch erhalten werden:
Collections.synchronizedMap(myMap);
Aber um diese Logik korrekt umzusetzen, brauchen Sie zusätzliche Synchronisation in der Form:
synchronized(myMap) {
if (!myMap.containsKey("tomato"))
myMap.put("tomato", "red");
}
Auch die Iteration über eine Hashtable
Einträge (oder eine HashMap
erhalten durch Collections.synchronizedMap
) ist nicht thread-sicher, es sei denn, Sie schützen auch die Map
vor Veränderungen durch zusätzliche Synchronisation zu schützen.
Implementierungen des ConcurrentMap
Schnittstelle (zum Beispiel ConcurrentHashMap
) lösen einen Teil dieser Probleme, indem sie Thread-sichere "Check-then-act"-Semantik wie zum Beispiel:
ConcurrentMap.putIfAbsent(key, value);
Beachten Sie auch, dass Iteratoren, die auf eine HashMap zeigen, ungültig werden, wenn diese geändert wird.
Gibt es also einen Unterschied zwischen synchronized(myMap) {...} und ConcurrentHashMap in Bezug auf Thread sicher?
Da ich einige Jahre inmitten eines JVM-Entwicklungsteams gearbeitet habe, kann ich sagen, dass die interne Synchronisierung von Hashtable zumindest nützlich ist, um den Finger auf den Code des Kunden zu legen, wenn er fragwürdigen nebenläufigen Code schreibt. Wir erhielten mehrere Beschwerden über Fehler innerhalb von HashMap (und damit "offensichtlich" einen JDK/JVM-Bug), wenn die Ursache eine gleichzeitige Änderung war.
Aus Hashtable javadoc (Hervorhebung hinzugefügt): "Ab der Java 2 Plattform v1.2 wurde diese Klasse umgerüstet, um die Map-Schnittstelle zu implementieren, zu einem Mitglied des Java Collections Framework ." Sie haben jedoch Recht, dass es sich um Legacy-Code handelt. Alle Vorteile der Synchronisierung können mit Collections.synchronizedMap(HashMap) effizienter genutzt werden. (Ähnlich wie Vector eine Legacy-Version von Collections.synchronizedList(ArrayList) ist).
@aberrant80: leider haben Sie keine Wahl zwischen den beiden und müssen Hashtable verwenden, wenn Sie für J2ME programmieren...
Diese Frage wird häufig in Vorstellungsgesprächen gestellt, um zu prüfen, ob der Bewerber die korrekte Verwendung von Sammelklassen versteht und sich der verfügbaren Alternativlösungen bewusst ist.
HashMap
Klasse entspricht in etwa der Hashtable
mit dem Unterschied, dass es nicht synchronisiert ist und Nullen zulässt. ( HashMap
erlaubt Nullwerte als Schlüssel und Wert, während Hashtable
erlaubt nicht null
s).HashMap
garantiert nicht, dass die Reihenfolge auf der Karte im Laufe der Zeit konstant bleibt.HashMap
nicht synchronisiert ist, während Hashtable
synchronisiert ist.HashMap
ist ausfallsicher, während der Enumerator für die Hashtable
nicht ist und werfen ConcurrentModificationException
wenn ein anderer Thread die Map strukturell verändert, indem er ein Element hinzufügt oder entfernt, außer Iterator
eigene remove()
Methode. Dies ist jedoch kein garantiertes Verhalten und wird von der JVM nach bestem Wissen und Gewissen durchgeführt.Hinweis auf einige wichtige Begriffe:
Hashtable
müssen eine Sperre für das Objekt erwerben, während andere darauf warten, dass die Sperre freigegeben wird.set
Methode, da sie die Sammlung nicht "strukturell" verändert. Wenn jedoch vor dem Aufruf der set
wurde die Sammlung strukturell verändert, IllegalArgumentException
geworfen werden.HashMap
kann synchronisiert werden durch
Map m = Collections.synchronizeMap(hashMap);
Map bietet Auflistungsansichten anstelle einer direkten Unterstützung für die Iteration über Aufzählungsobjekte. Auflistungsansichten erweitern die Ausdruckskraft der Schnittstelle erheblich, wie später in diesem Abschnitt erläutert wird. Mit Map können Sie über Schlüssel, Werte oder Schlüssel-Wert-Paare iterieren; Hashtable
bietet die dritte Möglichkeit nicht an. Map bietet eine sichere Möglichkeit, Einträge mitten in der Iteration zu entfernen; Hashtable
nicht. Schließlich behebt Map einen kleinen Mangel in der Hashtable
Schnittstelle. Hashtable
hat eine Methode namens contains, die true zurückgibt, wenn die Hashtable
einen bestimmten Wert enthält. Angesichts des Namens würde man erwarten, dass diese Methode true zurückgibt, wenn der Hashtable
einen bestimmten Schlüssel enthalten, da der Schlüssel der primäre Zugangsmechanismus für eine Hashtable
. Die Map-Schnittstelle beseitigt diese Quelle der Verwirrung durch Umbenennung der Methode containsValue
. Außerdem wird dadurch die Konsistenz der Schnittstelle verbessert. containsValue
parallelen containsKey
.
1) Die Iteratoren der HashMap sind NICHT ausfallsicher. Sie sind ausfallsicher. Es besteht ein großer Bedeutungsunterschied zwischen diesen beiden Begriffen. 2) Es gibt keine set
Operation an einer HashMap
. 3) Die put(...)
Operation wirft nicht IllegalArgumentException
wenn es eine frühere Änderung gab. 4) Das ausfallsichere Verhalten von HashMap
auch tritt auf, wenn Sie eine Zuordnung ändern. 5) Das ausfallsichere Verhalten es garantiert. (Was nicht garantiert ist, ist das Verhalten eines HashTable
wenn Sie eine gleichzeitige Änderung vornehmen. Das tatsächliche Verhalten ist ... unvorhersehbar.)
6) Hashtable
garantiert auch nicht, dass die Reihenfolge der Kartenelemente im Laufe der Zeit stabil bleibt. (Sie verwechseln vielleicht Hashtable
mit LinkedHashMap
.)
Macht sich noch jemand Sorgen darüber, dass Studenten heutzutage auf die irrige Idee kommen, dass "synchronisierte Versionen" der Sammlungen irgendwie bedeuten, dass man zusammengesetzte Operationen nicht mehr extern synchronisieren muss? Mein Lieblingsbeispiel dafür ist thing.set(thing.get() + 1);
die Neulinge oft als völlig ungeschützt überraschen, vor allem wenn die get()
y set()
sind synchronisierte Methoden. Viele von ihnen erwarten Magie.
HashMap
: Eine Implementierung des Map
Schnittstelle, die Hash-Codes zum Indizieren eines Arrays verwendet. Hashtable
: Hallo, 1998 hat angerufen. Sie wollen ihre Sammel-API zurück.
Aber im Ernst: Es ist besser, wenn Sie sich von folgenden Dingen fernhalten Hashtable
insgesamt. Für Single-Thread-Anwendungen brauchen Sie den zusätzlichen Overhead der Synchronisierung nicht. Bei hochgradig nebenläufigen Anwendungen kann die paranoide Synchronisierung zum Aushungern, zu Deadlocks oder zu unnötigen Pausen bei der Garbage Collection führen. Wie Tim Howland schon sagte, können Sie ConcurrentHashMap
stattdessen.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
45 Stimmen
HashTable ist in Java 1.7 veraltet und es wird empfohlen, die Implementierung von ConcurrentMap zu verwenden
9 Stimmen
@MissFiona Nein,
ConcurrentMap
es no notwendig, da in der Frage von "Nicht-Thread-Anwendungen" die Rede ist, was bedeutet, dass Threading/Concurrency kein Thema ist.9 Stimmen
@BasilBourque, Ja, aber ich glaube, was MissFiona damit meinte, war so etwas wie "
HashTable
wurde traditionell nur wegen seines partiellen Threading-Schutzes gewählt. Aber das wurde durchConcurrentHashMap
Daher gilt sie im Allgemeinen als im Ruhestand befindlich. Es wird allgemein empfohlen, zwischenHashMap
oConcurrentHashMap
." Und ich halte das für eine vernünftige Bemerkung, wenn sie es denn so gemeint hat.1 Stimmen
Nach Angaben von doi.org/10.48550/arXiv.1602.00984 Hashtable ist sowohl im Hinblick auf den Energieverbrauch als auch auf die Ausführungszeit effizienter als HashMap.