Voici le code de la fonction HASHCODE de chaîne de Java
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
4 Réponses :
Je ne travaille pas avec Java, mais cela ne semble pas être une "condition de race". Je dirais que c'est un "paresseux calculer le hash, et après cela, cache la valeur". p>
Ainsi, aucune utilisation pour calculer le hachage dans le constructeur, si personne n'appelera la méthode HashCode. Mais après que le premier appelle hashcode, la valeur est calculée, ne changera jamais, de sorte que vous pouvez le mettre en cache pour d'autres appels. P>
plus tard EDIT: P>
Maintenant, je vois ton point. C'est le but de la variable locale. Et n'utilisant pas un mécanisme "Safe Safe" est une "décision de performance", comme la création d'une serrure, l'utilise, la libération de celui-ci est un coût, tandis que le cas dont vous parlez (2 threads appelant hashcode en même temps) est un assez difficile à atteindre dans le scénario de la vie réelle et le résultat sera la même valeur de hachage. P>
Il y a une course de données, mais il est inoffensif car il retournera la même valeur de hachage dans toutes les discussions, quel que soit le thread gagne la course. La pire chose qui puisse arriver est de certains cycles de processeur gaspillés si deux ou plusieurs threads décident tous deux de faire le calcul.
théoriquement on peut générer du code qui provoquerait plusieurs threads simultanés pour lire le hachage de valeur 0 et entrer dans la partie de calcul. Ce serait "gaspillaud", mais sûr, car la fonction fonctionne sur les caractères immuables, et chaque instance calculerait exactement la même valeur de hachage. P>
A du sens, mais avez-vous une source qui montre qu'il n'y a pas de "écritures partielles" à l'entier qui peut être fait? Java Enterger est 32 bits, alors disons, d'avoir écrit 1 bit, puis de lire les 32 comme 0 à 0? Je me souviens de quelque chose à propos de CPUS bloquant l'accès à la mémoire dans des sections 32 bits, mais si cela supposerait que cet entier est correctement aligné sur un bloc de 1 32 bits au lieu de couvrant 2.
@ user1122069: L'accès entier à Java est garanti d'être atomique. Long n'est pas.
Théoriquement on peut générer du code qui entraînerait de lire plusieurs threads simultanés à lire le 0 - est-ce une sorte de condition de race "sûre"?
@DMITRYZAGORULKIN - Discussions multiples Lecture de la même variable, sans aucun écrit impliqué n'est pas une condition de course du tout. Il est parfaitement sûr de faire. Quand écrit entrer en jeu, vous devez considérer les barrières / verrouillage / etc ...
Il est également utile de mentionner que HashCode calcule de la valeur immuable, il est donc threadsafe pour la calculer
lecture et écriture sur Si plusieurs threads écrivent sur Dans ce sens, le résultat est déterministe. Dans le même temps, il n'est pas nécessaire de synchroniser des threads pour partager cette instance. Supposons que vous auriez une clé hashcode code> n'est pas correctement synchronisé en fonction du modèle de mémoire Java, mais il est néanmoins sûr. P>
Hashcode code> en raison de l'immuabilité d'un objet code> de chaîne code>, il est implicite que le calcul donne le même résultat. Supposons que ce résultat est x code> puis n'importe quel thread est garanti pour observer soit 0 code> ou x code> car int code> est atomique sur Tous les VMS. Si un thread observe 0 code>, il recalcule simplement le code de hachage qui est garanti pour générer x code>, ne réinitialisant ainsi que la valeur si un autre thread a appliqué l'opération simultanément ou dans son Cache de fil-local. P>
"foo" code> dans votre application utilisée par tous vos threads. En raison de la déduplication de chaîne de Java, cette constante de chaîne serait partagée entre tous vos threads qui devraient se synchroniser uniquement pour les sauvegarder les problèmes pour recompagner les codes de hachage. Le calcul du code de hachage est toutefois une opération très bon marché, tandis que la synchronisation est très coûteuse. Comme l'exactitude est donnée, cette optimisation a du sens. P>
Pour résumer les résultats de la section Commentaires - Lectures et écrit de l'entier sont effectués atomicly dans la machine virtuelle Java. P>
La spécification assortie peut être trouvée sous "Accès atomique" sur le site Web Oracle. P>
https://docs.oracle.com/javase/tatuuteur /essential/concurrency/atomic.html p>
Je pense que le
hash = h code> est le thread-coffre-fort (il y aura 0 ou la valeur deh code> dans la variablehachage code>, rien d'autre) et tous les autres n'a pas d'importance. Peu importe, car si je compte le hachage plusieurs fois, ce sera le même, toujours.@Nagyvilmos J'avais l'impression que vous pouviez lire une valeur de mémoire partiellement écrite. Ce serait un processeur et non dépendant de la langue et je n'ai pas de source pour cela. Aimerait comprendre cela cependant. Ceci = 0 et aucun modèle de verrouillage n'est un bon si c'est correct.
@ user1122069 uniquement pour
long code> etdouble code> une valeur partiellement écrite est possible.@ user1122069 Comme @Bowmore mentionné, le JVM écrit atomiquement toutes les primitives, à l'exception du
long code> etdouble code>. Je ne suis pas sûr, mais sur les architectures 64 bits, ces deux deux sont rédigés atmériquement.L'algorithme est idempotent, donc si un fil ne voit pas la valeur code> code> définie dans un autre thread, il calcule simplement la même valeur que l'autre thread. Il est impossible pour la méthode de renvoyer une valeur différente.
@Nagyvilmos merci. Il s'agit donc d'une caractéristique de la droite JVM et ne serait pas vraie pour une langue comme c, sauf peut-être avec des types de 1 bits?
Dans 64 bits JVM, même long et double sont le fil sûr, car un cycle de processeur peut traiter, mais nous ne pouvons évidemment pas dépendre de la JVM afin de cohérence, d'utiliser des mots-clés volatils. archive.is/puaaf#selection-8433.107-8437.73