Paramètres du constructeur ConcurrentHashMap?

Je m’interroge sur les parameters de construction d’un ConcurrentHashMap :

  • initialCapacity est 16 par défaut (compris).
  • loadFactor est 0.75 par défaut.
  • concurrencyLevel est 16 par défaut.

Mes questions sont:

  • Quels critères utiliser pour ajuster loadFactor vers le haut ou le bas?
  • Comment pouvons-nous établir le nombre de threads mis à jour simultanément?
  • Quels critères doivent être utilisés pour ajuster la concurrencyLevel up ou down?

Aditionellement:

  • Quelles sont les caractéristiques d’une bonne implémentation du hashcode? (Si une question SO aborde cette question, il suffit de lien vers elle.)

Je vous remercie!

La réponse courte: définissez “capacité initiale” sur le nombre approximatif de mappages que vous comptez mettre dans la carte et laissez les autres parameters à leurs valeurs par défaut.

Longue réponse:

  • facteur de charge est le rapport entre le nombre de “godets” dans la carte et le nombre d’éléments attendus;

  • 0.75 est généralement un compromis raisonnable – si je me souviens bien, cela signifie qu’avec une bonne fonction de hachage, nous attendons en moyenne environ 1.6 redirections pour trouver un élément dans la carte (ou autour de ce chiffre);

    • changer le facteur de charge change le compromis entre plus de redirections pour trouver un élément mais moins d’espace gaspillé – put 0.75 est généralement une bonne valeur;

    • en principe, réglez ConcurrencyLevel sur le nombre de threads simultanés dont vous prévoyez de modifier la carte, bien que surestimer cela ne semble pas avoir un effet négatif autre que gaspiller de la mémoire (j’ai écrit un peu sur les performances de ConcurrentHashMap au cas où re intéressé)

De manière informelle, votre fonction de hachage devrait essentiellement viser à avoir autant de “hasard” dans les bits que possible. Ou plus ssortingctement, le code de hachage pour un élément donné devrait donner à chaque bit environ 50% de chance d’être défini. Il est en fait plus facile d’illustrer cela avec un exemple: encore une fois, vous pourriez être intéressé par des choses que j’ai écrites sur le fonctionnement de la fonction de hachage de Ssortingng et les directives associées sur les fonctions de hachage . Les commentaires sont évidemment les bienvenus pour tout ce genre de choses.

Une chose que je mentionne aussi à un moment donné est que vous ne devez pas être trop paranoïaque dans la pratique: si votre fonction de hachage produit une quantité “raisonnable” de hasard dans certains des bits, alors ça ira souvent. Dans le pire des cas, coller des données représentatives dans une chaîne et prendre le code de hachage de la chaîne ne fonctionne pas si mal.

Le facteur de charge est principalement lié à la qualité de la fonction de hachage. Plus le facteur de charge est proche de zéro, moins il y a de risques de collision, même si la fonction de hachage n’est pas très performante. Le compromis est que l’empreinte mémoire est plus grande. En d’autres termes, le HashMap ne dissortingbue pas les entrées dans des compartiments séparés pour chaque code de hachage séparé, il les regroupe par proximité, donc plus il y a de compartiments, plus la dissortingbution est étendue, moins il y a de collisions.

Vous devez donc jouer avec le facteur de charge pour améliorer le temps de recherche ou réduire la mémoire, en fonction de vos besoins et des objects que vous stockez dans la Carte.

ConcurrencyLevel dépend vraiment de votre application. Si vous ne disposez que de deux ou trois threads dans l’application, allez-y. Si vous êtes un serveur d’applications avec un nombre arbitraire de threads, vous devez comprendre quelle est votre capacité de charge et pour quel point vous souhaitez optimiser.

Une implémentation de hashcode de bonne qualité fournit une dissortingbution aussi large que possible des valeurs possibles de l’object avec le moins de collisions, tout en respectant le contrat. En d’autres termes, cela permet à HashMap (ou à Set, selon le cas) de répartir les objects dans des compartiments distincts, accélérant ainsi les recherches.

loadFactor: contrôle quand l’implémentation décide de redimensionner la hashtable. Une valeur trop élevée gaspillera de l’espace; une valeur trop faible entraînera des opérations de redimensionnement coûteuses.

concurrencyLevel: indique à l’implémentation d’essayer d’optimiser le nombre donné de threads en écriture. Selon les docs de l’API, le fait de ne pas utiliser le facteur 10 ne devrait pas avoir beaucoup d’effet sur les performances.

La concurrence autorisée entre les opérations de mise à jour est guidée par l’argument facultatif du constructeur concurrencyLevel (par défaut, 16), utilisé comme indice pour le dimensionnement interne. La table est partitionnée en interne pour tenter d’autoriser le nombre indiqué de mises à jour simultanées sans conflit. Étant donné que le placement dans les tables de hachage est essentiellement aléatoire, la concurrence réelle variera. Idéalement, vous devriez choisir une valeur pour gérer autant de threads que jamais modifier simultanément la table. L’utilisation d’une valeur nettement supérieure à celle dont vous avez besoin peut entraîner une perte de temps et d’espace, et une valeur nettement inférieure peut entraîner des conflits de threads. Mais surestimer et sous-estimer dans un ordre de grandeur n’a généralement pas beaucoup d’impact notable.

Une bonne implémentation de hashcode dissortingbuera les valeurs de hachage uniformément sur n’importe quel intervalle. Si le jeu de clés est connu à l’avance, il est possible de définir une fonction de hachage “parfaite” qui crée une valeur de hachage unique pour chaque clé.

loadFactor est défini à 0,75 par défaut, quels critères faut-il utiliser pour ajuster cela à la hausse ou à la baisse?

Avant de pouvoir comprendre comment cela fonctionne, vous devez connaître le fonctionnement des cartes de hachage. La carte est essentiellement une série de seaux. Chaque valeur de la carte est placée dans un compartiment en fonction de son code de hachage. Le loadFactor signifie que si les compartiments sont remplis à plus de 75%, la carte doit être redimensionnée

concurrencyLevel est défini sur 16 par défaut, comment établir le nombre de threads à mettre à jour simultanément? Quels critères devraient être utilisés pour ajuster cela à la hausse ou à la baisse?

Ceci demande combien de threads devraient modifier la carte simultanément (simultanément)

Pour les codes de hachage, voir Effective Java de Joshua Bloch