web-dev-qa-db-fra.com

Différence entre Hashtable et Collections.synchronizedMap (HashMap)

Pour autant que je sache, Java.util.Hashtable synchronise chaque méthode de l'interface Java.util.Map , tandis que Collections.synchronizedMap(hash_map) retourne un objet wrapper contenant des méthodes synchronisées déléguant les appels au réel hash_map (corrigez-moi si je me trompe).

J'ai deux questions:

  1. Quelle différence cela fait-il de synchroniser chaque méthode et d'avoir une classe wrapper? Quels sont les scénarios pour choisir l'un plutôt que l'autre?

  2. Que se passe-t-il lorsque nous faisons Collections.synchronizedMap(hash_table)? Est-ce que cela équivaut à simplement utiliser un Java.util.Hashtable Normal?

45
Vinoth Kumar C M

Voici les réponses que j'ai obtenues d'un peu de recherche (espérons-le correcte):

  1. Les deux offrent le même degré de synchronisation. Si vous deviez envelopper Hashtable via Collections.synchronized, vous auriez le même degré, mais avec une autre couche redondante, de synchronisation.

  2. La principale différence entre Hashtable et Collections.synchronizedMap(HashMap) existe davantage au niveau de l'API. Parce que Hashtable fait partie du code hérité de Java, vous verrez que l'API Hashtable est améliorée pour implémenter l'interface Map, pour faire partie du framework de collections Java. Cela signifie que si vous deviez envelopper Hashtable à Collections.synchronizedMap(), l'API du Hashtable encapsulé deviendrait limitée à l'API Map. Donc, si l'API de Hashtable est incluse dans votre définition de comportement, alors elle est évidemment modifiée/limitée.

15
Nadir Muzaffar

Une autre différence que je peux trouver lors de l'implémentation des deux classes est la suivante:

• La classe Hashtable a toutes ses méthodes synchronisées, c'est-à-dire que le verrouillage est fait au niveau de la méthode et donc on peut dire que le mutex est toujours à l'objet Hashtable ( this) niveau.

• La méthode Collections.synchronizedMap(Map) renvoie une instance de SynchronizedMap qui est une classe interne à la classe Collections. Cette classe a toutes ses méthodes dans un bloc Synchronized avec un mutex. La différence réside ici dans le mutex. La classe interne SynchronizedMap a deux constructeurs, un qui ne prend que Map comme argument et un autre qui prend un Map et un Object (mutex) comme un argument. Par défaut, si l'on utilise le premier constructeur de passer uniquement un Map, this est utilisé comme mutex. Cependant, le développeur est autorisé à passer un autre objet de mutex comme deuxième argument par lequel le verrou sur les méthodes Map serait uniquement sur ce Object et donc moins restrictif que Hashtable.

• Par conséquent, Hashtable utilise la synchronisation au niveau de la méthode mais Collections.synchronizedMap(Map) offre une flexibilité pour verrouiller le développeur sur le mutex fourni avec le bloc Synchronized.

60
mankadnandan

La première classe de collection associative à apparaître dans la bibliothèque de classes Java était Hashtable, qui faisait partie de JDK 1.0. Hashtable a fourni une capacité de carte associative facile à utiliser et sécurisée pour les threads. était certainement pratique. Cependant, la sécurité des threads avait un prix - toutes les méthodes de Hashtable étaient synchronisées. À cette époque, la synchronisation non intentionnelle avait un coût de performance mesurable. Le successeur de Hashtable, HashMap, qui apparaissait dans le cadre des collections dans JDK 1.2, traitait la sécurité des threads en fournissant une classe de base non synchronisée et un wrapper synchronisé, Collections.synchronizedMap. La séparation de la fonctionnalité de base du thread-safety Collections.synchronizedMap permettait aux utilisateurs qui avaient besoin d'une synchronisation de l'avoir, mais les utilisateurs qui ne l'ont pas fait besoin il n'a pas eu à payer pour cela.

L'approche simple de synchronisation adoptée à la fois par Hashtable et synchronizedMap - la synchronisation de chaque méthode sur Hashtable ou l'objet wrapper de carte synchronisée - présente deux lacunes principales. C'est un obstacle à l'évolutivité, car un seul thread peut accéder à la table de hachage à la fois. Dans le même temps, il est insuffisant pour assurer une véritable sécurité des threads, dans la mesure où de nombreuses opérations composées courantes nécessitent encore une synchronisation supplémentaire. Alors que des opérations simples telles que get () et put () peuvent se terminer en toute sécurité sans synchronisation supplémentaire, il existe plusieurs séquences d'opérations courantes, telles que l'itération ou la mise-si-absent, qui nécessitent toujours une synchronisation externe pour éviter les courses de données.

Le lien suivant est la source et contient plus d'informations: Classes de collections simultanées

4
bchetty

La différence n'est pas tout au niveau évident de l'API et il existe de nombreuses subtilités au niveau de l'implémentation. Par exemple, Hashtable ne possède pas le recalcul avancé de HashMap des codes de hachage des clés fournies qui réduit les collisions de hachage. D'un autre côté, Hashtable#hashCode() évite la récursion infinie des tables de hachage autoréférentielles pour permettre à "certaines applets de l'ère 1.1 avec des tables de hachage autoréférentielles de fonctionner".

En général, cependant, il ne faut pas compter sur Hashtable pour recevoir d'autres améliorations ou raffinements au-delà de l'exactitude de base et de la compatibilité descendante. Il est considéré comme une relique du passé profond Java passé.

3
Marko Topolnik

Un autre point de différence à noter est que HashTable ne permet pas les clés ou les valeurs nulles alors que HashMap autorise une clé nulle et un nombre illimité de valeurs nulles. Puisque synchronizedMap est wrapper sur HashMap, son comportement par rapport aux valeurs et clés nulles est le même que HashMap.

2
Rahul Jangra

Au risque d'énoncer l'évidence (ou de se tromper) n'est pas la différence que

Les wrappers de synchronisation ajoutent une synchronisation automatique (thread-safety) à une collection arbitraire

http://docs.Oracle.com/javase/tutorial/collections/implementations/wrapper.html et continue de dire

Une collection créée de cette manière est tout aussi sûre pour les threads qu'une collection normalement synchronisée, telle qu'un vecteur.

Vous aimerez peut-être voir ce fil pour les problèmes concernant les HashMaps et la concurrence - problème de concurrence Hashmap (ou vous les connaissez peut-être déjà très bien). Un bon exemple est:

Les conditions que vous décrivez ne seront pas remplies par HashMap. Étant donné que le processus de mise à jour d'une carte n'est pas atomique, vous pouvez rencontrer la carte dans un état non valide. Plusieurs écritures peuvent le laisser dans un état corrompu. ConcurrentHashMap (1.5 ou version ultérieure) fait ce que vous voulez.

https://stackoverflow.com/a/1003071/201648

Je suppose qu'en termes de "quand dois-je utiliser cela", j'aurais tendance à utiliser la collection synchronisée où la concurrence est requise, sinon vous pourriez créer plus de travail pour vous-même (voir ci-dessous).

En termes de modification du comportement

Si un itérateur explicite est utilisé, la méthode itérateur doit être appelée à partir du bloc synchronisé. Le non-respect de ces conseils peut entraîner un comportement non déterministe

Il y a plus de conséquences de l'utilisation de la synchronisation donnée sur le lien (Oracle) fourni.

1
Aaron Newton