7
votes

La «chaîne» de Java est-elle du fil-coffre-fort si son cache Setter n'utilise pas de serrures?

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;
    }


7 commentaires

Je pense que le hash = h est le thread-coffre-fort (il y aura 0 ou la valeur de h dans la variable hachage , 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 et double une valeur partiellement écrite est possible.


@ user1122069 Comme @Bowmore mentionné, le JVM écrit atomiquement toutes les primitives, à l'exception du long et double . 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 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


4 Réponses :


0
votes

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".

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.

plus tard EDIT:

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.


1 commentaires

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.



11
votes

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.


5 commentaires

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



1
votes

lecture et écriture sur hashcode n'est pas correctement synchronisé en fonction du modèle de mémoire Java, mais il est néanmoins sûr.

Si plusieurs threads écrivent sur Hashcode en raison de l'immuabilité d'un objet de chaîne , il est implicite que le calcul donne le même résultat. Supposons que ce résultat est x puis n'importe quel thread est garanti pour observer soit 0 ou x car int est atomique sur Tous les VMS. Si un thread observe 0 , il recalcule simplement le code de hachage qui est garanti pour générer x , 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.

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é "foo" 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.


0 commentaires

1
votes

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.

La spécification assortie peut être trouvée sous "Accès atomique" sur le site Web Oracle.

https://docs.oracle.com/javase/tatuuteur /essential/concurrency/atomic.html


0 commentaires