thread synchronizedmap safe current concurrent java hashcode concurrenthashmap

java - synchronizedmap - ¿Parámetros del constructor ConcurrentHashMap?



thread safe hashmap (4)

loadFactor se establece en 0.75 de forma predeterminada, ¿qué criterios deben usarse para ajustar esto hacia arriba o hacia abajo?

Necesita algunos antecedentes sobre cómo funcionan los mapas hash antes de poder entender cómo funciona esto. El mapa es esencialmente una serie de cubos. Cada valor en el mapa se coloca en un cubo dependiendo de cuál es su código hash. El factor loadFactor significa que, si los cubos están llenos en más del 75%, el mapa debería cambiar de tamaño.

concurrencyLevel se establece en 16 de forma predeterminada, ¿cómo establecemos el número de subprocesos que se actualizan simultáneamente? ¿Qué criterios deben usarse para ajustar esto hacia arriba o hacia abajo?

Esto le pregunta a cuántos subprocesos espera modificar el Mapa simultáneamente (simultáneamente)

Para los códigos de hash, vea la Eficaz Java de Joshua Bloch

Me pregunto sobre los parámetros para construir un ConcurrentHashMap :

  • initialCapacity es 16 por defecto (entendido).
  • loadFactor es 0.75 por defecto.
  • concurrencyLevel es 16 por defecto.

Mis preguntas son:

  • ¿Qué criterios deben usarse para ajustar loadFactor hacia arriba o hacia abajo?
  • ¿Cómo establecemos el número de subprocesos que se actualizan simultáneamente?
  • ¿Qué criterios deben usarse para ajustar la concurrencyLevel hacia arriba o hacia abajo?

Adicionalmente:

  • ¿Cuáles son las características de una buena implementación de hashcode? (Si una pregunta SO aborda esto, simplemente enlácela).

¡Gracias!


El factor de carga está relacionado principalmente con la calidad de la función hash. Cuanto más cercano a cero sea el factor de carga, es menos probable que haya colisiones, incluso si la función hash no es tan buena. La compensación es que la huella de memoria es mayor. En otras palabras, el HashMap no distribuye las entradas en compartimientos separados para cada código hash separado, los agrupa por proximidad, por lo que cuantos más cubos tiene, más distribuida está la distribución, menos probable es que haya colisiones.

Por lo tanto, la conclusión es que usted juega con el factor de carga para mejorar el tiempo de búsqueda o reducir la memoria, de acuerdo con sus necesidades y los objetos que está almacenando en el Mapa.

ConcurrencyLevel realmente depende de tu aplicación. Si solo tienes dos o tres subprocesos ejecutándose en la aplicación, ahí tienes. Si usted es un servidor de aplicaciones con un número arbitrario de subprocesos, entonces necesita comprender cuál es su capacidad de carga y para qué punto desea optimizar.

Una implementación de código de hash de buena calidad proporciona una distribución lo más amplia posible entre los valores posibles del objeto con el menor número de colisiones, mientras se respeta el contrato. En otras palabras, permite que el HashMap (o el conjunto según sea el caso) distribuya los objetos en grupos separados para que las búsquedas sean más rápidas.


La respuesta corta: configure la "capacidad inicial" a aproximadamente la cantidad de asignaciones que espera colocar en el mapa y deje los otros parámetros en su valor predeterminado.

Respuesta larga:

  • el factor de carga es la relación entre el número de "cubetas" en el mapa y el número de elementos esperados;

  • 0.75 suele ser un compromiso razonable: como recuerdo, significa que con una buena función hash, en promedio esperamos que aproximadamente 1.6 redirecciones encuentren un elemento en el mapa (o alrededor de esa figura);

    • cambiar el factor de carga cambia el compromiso entre más redireccionamientos para encontrar un elemento pero menos espacio desperdiciado; poner 0.75 generalmente es un buen valor;

    • en principio, establezca ConcurrencyLevel en el número de subprocesos simultáneos que espera modificar el mapa, aunque sobreestimar esto no parece tener un efecto negativo más que perder memoria (escribí un poco sobre el rendimiento de HashMap de Concurrent hace un tiempo, por si acaso re interesado

De manera informal, su función hash debe apuntar esencialmente a tener tanta "aleatoriedad" en los bits como sea posible. O más estrictamente, el código hash para un elemento dado debería dar a cada bit aproximadamente un 50% de probabilidad de ser establecido. En realidad, es más fácil ilustrar esto con un ejemplo: de nuevo, puede que te interesen algunas cosas que escribí acerca de cómo funciona la función de hash de String y las pautas de función de hash asociadas. La retroalimentación es obviamente bienvenida en cualquiera de estas cosas.

Una cosa que también menciono en algún momento es que no tiene que ser demasiado paranoico en la práctica: si su función hash produce una cantidad "razonable" de aleatoriedad en algunos de los bits, entonces a menudo estará bien. En el peor de los casos, pegar fragmentos de datos representativos en una cadena y tomar el código hash de la cadena realmente no funciona tan mal.


loadFactor: controla cuando la implementación decide cambiar el tamaño de la tabla hash. Un valor demasiado alto desperdiciará espacio; un valor demasiado bajo resultará en costosas operaciones de cambio de tamaño.

concurrencyLevel: le dice a la implementación que intente optimizar para el número dado de subprocesos de escritura. De acuerdo con los documentos de la API, estar fuera por hasta un factor de 10 no debería tener mucho efecto en el rendimiento.

La concurrencia permitida entre las operaciones de actualización está guiada por el argumento opcional de constructor concurrencyLevel (valor predeterminado 16), que se usa como una sugerencia para el tamaño interno. La tabla está particionada internamente para intentar permitir el número indicado de actualizaciones concurrentes sin disputa. Debido a que la ubicación en las tablas hash es esencialmente aleatoria, la concurrencia real variará. Idealmente, debería elegir un valor para acomodar tantos subprocesos como siempre modificará la tabla al mismo tiempo. El uso de un valor significativamente más alto del que necesita puede desperdiciar espacio y tiempo, y un valor significativamente menor puede llevar a la contención de hilos. Pero las sobreestimaciones y subestimaciones en un orden de magnitud no suelen tener un impacto notable.

Una buena implementación de hashcode distribuirá los valores de hash de manera uniforme en cualquier intervalo. Si el conjunto de claves se conoce de antemano, es posible definir una función hash "perfecta" que crea un valor de hash único para cada clave.