2012-01-16 21 views
35

Por lo que sé, java.util.Hashtable sincroniza todos y cada método de la interfaz java.util.Map, mientras Collections.synchronizedMap(hash_map) devuelve un objeto contenedor que contiene métodos sincronizados delegación de llamadas a la actual hash_map (corregir si me estoy equivocado).Diferencia entre Hashtable y Collections.synchronizedMap (HashMap)

Tengo dos preguntas:

  1. Qué diferencia hace para sincronizar todos y cada método y para tener una clase de contenedor? ¿Cuáles son los escenarios para elegir uno sobre el otro?

  2. ¿Qué sucede cuando hacemos Collections.synchronizedMap(hash_table)? ¿Será esto igual a simplemente usar un java.util.Hashtable normal?

+0

posible duplicado de [Diferencias entre HashMap y Hashtable?] (Http://stackoverflow.com/questions/40471/differences-between-hashmap-and-hashtable) –

+13

Esto no es un duplicado de * esa * pregunta. Esto es comparar el contenedor sincronizado sobre un HashMap (o HashTable) con un HashTable. –

+0

Me interesaría saber si existen diferencias en el rendimiento, que ninguna de las respuestas actuales aborda. Los métodos de llamada de un 'Collections.synchronizedMap' a través de una variable de tipo Map significa que hay 2 llamadas virtuales de interfaz antes de llegar a la implementación, mientras que con Hashtable, hay como máximo 1 llamada virtual, y puede declarar su variable como tipo Hashtable directamente, y hazlo con 0 llamadas virtuales. Pero quizás HashMap difiera de otras formas que lo hacen más rápido en general. – Boann

Respuesta

13

Estas son las respuestas que he recibido de un poco de investigación (esperemos correcta):

  1. ambos proporcionan el mismo grado de sincronización. Si tuviera que ajustar Hashtable a través de Collections.synchronized tendría el mismo grado, pero con otra capa redundante, de sincronización.

  2. La diferencia principal entre Hashtable y Collections.synchronizedMap(HashMap) existe más en el nivel de la API. Como Hashtable es parte del código heredado de Java, verá que la API Hashtable se ha mejorado para implementar la interfaz Map, para formar parte del marco de colecciones de Java. Esto significa que si tuviera que ajustar Hashtable a través de Collections.synchronizedMap(), la API del Hashtable envuelto se limitaría a la API Map. Entonces, si la API de Hashtable está incluida en su definición de comportamiento , entonces obviamente está alterada/limitada.

1

A riesgo de afirmar lo obvio (o ser mal llano) no es la diferencia de que

Las envolturas de sincronización añaden sincronización automática (hilo de seguridad) a una colección arbitraria

http://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html y continúa decir

Una colección creada de esta manera es tan segura para subprocesos como una colección normalmente sincronizada, como un Vector.

Puede que desee ver este hilo para los problemas relacionados con HashMaps y la concurrencia - Hashmap concurrency issue (o posiblemente ya esté muy consciente de ellos). Un buen ejemplo es:

Las condiciones que describe no serán satisfechas por HashMap. Dado que el proceso de actualización de un mapa no es atómico, puede encontrar el mapa en un estado no válido. Las escrituras múltiples pueden dejarlo en un estado corrupto. ConcurrentHashMap (1.5 o posterior) hace lo que quiere.

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

supongo que en términos de "cuándo debo utilizar este" yo tendería a utilizar la colección Syncronised donde se requiere la concurrencia, de lo contrario puede ser la creación de más trabajo para ti (véase más adelante).

En términos de alterar el comportamiento

Si se utiliza un iterador explícita, el método iterador debe ser llamado desde dentro del bloque sincronizado. Si no sigue este consejo puede como resultado un comportamiento no determinista

Hay más consecuencias del uso de la sincronización dada en el enlace (Oracle), siempre.

4

La primera clase de colección asociativa que aparece en la biblioteca de la clase Java era Hashtable, que formaba parte de JDK 1.0. Hashtable proporcionó una capacidad de mapa asociativo fácil de usar y segura para hilos, y fue ciertamente conveniente. Sin embargo, la seguridad del hilo tuvo un precio: todos los métodos de Hashtable se sincronizaron. En ese momento, la sincronización no atendida tenía un costo de rendimiento mensurable. El sucesor de Hashtable, HashMap, que apareció como parte del marco Colecciones en JDK 1.2, se ocupó de la seguridad de subprocesos al proporcionar una clase base no sincronizada y un contenedor sincronizado, Collections.synchronizedMap. Al separar la funcionalidad base de , el thread-safety Collections.synchronizedMap permitió a los usuarios que necesitaban la sincronización tenerlo, pero los usuarios que no lo necesitaban no tenían para pagarlo.

El enfoque simple para la sincronización tomada por tanto Hashtable y synchronizedMap - sincronizar cada método en el Hashtable o el objeto envoltorio sincronizado Mapa - tiene dos deficiencias principales. Es es un impedimento para la escalabilidad, porque solo un subproceso puede acceder a la tabla hash a la vez. Al mismo tiempo, es insuficiente para proporcionar seguridad verdadera de subprocesos, ya que muchas operaciones compuestas comunes aún requieren sincronización adicional. Mientras que operaciones simples como como get() y put() pueden completarse de manera segura sin sincronización adicional , existen varias secuencias comunes de operaciones, tales como iteración o put-si-ausente, que aún requieren sincronización externa para evitar carreras de datos .

El siguiente enlace es la fuente y tiene más información: Concurrent Collections Classes

+1

El segundo párrafo dice que 'Hashtable' y' synchronizedMap' es lo mismo. Lo que significa que no hemos respondido la pregunta en absoluto: ¿Cuál es su diferencia? – Pacerier

+0

lea la respuesta por @mankadnandan –

3

La diferencia no es todo a nivel de API obvia y hay muchas sutilezas en el nivel de aplicación. Por ejemplo, Hashtable no tiene el recálculo avanzado de HashMap de los códigos hash de las claves suministradas que reducen las colisiones hash. Por otro lado, Hashtable#hashCode() evita la recursión infinita de hashtables autorreferenciales para permitir el funcionamiento de "determinados subprogramas de la era 1.1 con tablas hash autorreferenciales".

En general, sin embargo, uno no debe contar con Hashtable recibiendo más mejoras o refinamientos más allá de la corrección básica y la compatibilidad con versiones anteriores. Se considera una reliquia del pasado profundo de Java.

45

Una de las diferencias más que puedo encontrar en la aplicación tanto de las clases es el siguiente:

• La clase Hashtable ha todos sus métodos sincronizados es decir, el bloqueo se realiza en el nivel de método y por lo tanto se puede decir que el mutex es siempre en el objeto Hashtable (this) level.

• El método Collections.synchronizedMap(Map) devuelve una instancia de SynchronizedMap que es una clase interna para la clase Collections. Esta clase tiene todos sus métodos en un bloque Synchronized con un mutex. La diferencia radica en el mutex aquí. La clase interna SynchronizedMap tiene dos constructores, uno que toma solo Map como argumento y otro que toma un Map y un Object (mutex) como argumento. De forma predeterminada, si se usa el primer constructor de aprobación solo se usa Map, this como mutex. Sin embargo, el desarrollador puede pasar otro objeto de exclusión mutua como segundo argumento por el cual el bloqueo en los métodos Map sería solo en ese Object y por lo tanto menos restrictivo que Hashtable.

• Por lo tanto, Hashtable utiliza la sincronización de nivel de método, pero Collections.synchronizedMap(Map) proporciona una flexibilidad para el bloqueo del desarrollador en el mutex proporcionado con el bloque Synchronized.

+2

¡Qué hermosa respuesta, subrayando lo que queda intacto de lo contrario en respuestas de descanso. +1 –

+3

Constructor extra y sincronización a nivel de bloque (a diferencia del nivel de método para HashTable) son las claves. –

+3

Esta es información realmente interesante, pero la clase SynchronizedMap interna es privada, y no hay un método estático correspondiente a la versión del constructor que acepta un objeto mutex como argumento, por lo que el desarrollador no puede proporcionar un mutex personalizado, ¿verdad? – CarLuva

Cuestiones relacionadas