4
votes

Comment sécuriser les threads de classe Java?

J'ai une classe java comme ci-dessous

 class User {

    String name;
    String phone;

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

}

La façon dont cette classe est utilisée est, pour chaque thread, 1 objet de cette classe User est créé. Maintenant qu'il y a une copie d'objet pour chaque thread, puis-je appeler cette classe comme thread safe?

Dois-je synchroniser ces méthodes?


4 commentaires

Vous ne devez synchroniser que lorsque plusieurs threads partagent une ressource et si chaque thread a sa propre copie d'objet, vous n'avez pas besoin de synchronisation.


Si chaque thread entrant a sa propre instance de la classe, alors vous n'avez pas à vous soucier de la sécurité des threads, en supposant que seul le thread propriétaire de l'instance y accède.


C'est une question vraiment compliquée. La réponse simple est de rendre la classe immuable (tous les champs finaux), ce qui est thread-safe et une bonne idée chaque fois que cela est pratique de toute façon.


dzone.com/articles/7-techniques-for-thread-safe- cours


3 Réponses :


0
votes

De la façon dont vous l'avez présenté, si chaque thread a sa seule copie, alors il peut être appelé thread-safe, car le maximum de threads d'accès est un.

Autre chose: si vous déclarez vos champs comme private et créez l'instance de cette classe comme final , alors il est immuable ( final User user = new User (...) ). Il n'y a pas de setters, donc l'objet ne peut pas être modifié ni changer sa référence. Si vous vouliez conserver l'immuabilité, vous devrez obliger les setters à renvoyer une nouvelle instance de cet objet avec des champs modifiés.

@markspace a remarqué que la meilleure approche serait de déclarer les champs comme finaux, car si vous utilisez le précédent et faites de User un membre d'une classe, cela ne fonctionnera pas (à moins que ce ne soit final) .


5 commentaires

Pas l'objet, non. Les champs eux-mêmes doivent être déclarés final . Les champs finaux ont une sémantique spéciale de visibilité de la mémoire, tout comme volatile et la JVM ne rend pas l'objet immuable à moins que les champs ne soient déclarés final .


Oui c'est vrai. Et que diriez-vous du cas que j'ai montré? L'objet final sans méthodes le modifiant n'est-il pas immuable?


Sauf si vous voulez dire autre chose, vous ne pouvez pas obtenir un objet immuable simplement en déclarant classe finale . Les champs eux-mêmes doivent être définitifs. Voici un lien vers la spécification, notez que le titre de cette section est «Sémantique finale du champ», la spécification ne définit que les objets immuables (et thread-safe) pour ce cas. Il ne suffit pas de changer une valeur. docs.oracle.com/javase/ specs / jls / se10 / html / jls-17.html # jls-1‌ 7.5


Je veux dire l'instance finale , côté client: utilisateur final user = new ...


OK, vous devriez clarifier votre réponse, il semble que vous disiez quelque chose de différent. Mais soyez prudent car si user n'est pas un champ (disons si c'est une variable locale) alors le mot-clé final ne fait rien de spécial.



1
votes

Pour qu'une classe soit thread-safe, quel que soit le nombre de threads qui y accèdent, ses invariants et post-conditions doivent être vérifiés.

Pour cette classe, bien qu'il n'y ait pas de méthode d'écriture, vous devez toujours synchroniser les lectures. C'est parce que le compilateur peut mettre en cache les variables d'état (dans ce cas name et phone ) pour chaque thread (rappelez-vous que chaque thread a son propre ensemble de registres). Ainsi, si un thread met à jour la valeur de l'une des variables d'état, l'autre thread peut ne pas la voir et il peut lire une valeur périmée.

Un moyen très simple d'éviter cela serait de créer l'état variables volatiles . C'est une primitive de synchronisation faible cependant, et ne fournit pas de comportement atomique comme le fait synchronized .

Voici la bonne façon de sécuriser ce thread de classe:

 class User {

    volatile String name;
    volatile String phone;

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

}

Remarque: chaque variable d'état peut utiliser un verrou différent, en fonction de vos besoins. J'ai supposé que ces deux variables participent d'une manière ou d'une autre à un invariant ensemble.

Synchronisation faible:

 class User {

    GuardedBy("this")String name;
    GuardedBy("this")String phone;

    public synchronised String getName() {
        return name;
    }

    public synchronised String getPhone() {
        return phone;
    }

}

Pour les méthodes synchronisées , chaque fois qu'un thread les appelle, il vide son cache et lit la dernière valeur de la mémoire, et chaque fois qu'il existe une méthode synchronisée , il met les dernières valeurs des variables en mémoire. p >

Les lectures obsolètes peuvent être encore plus dangereuses avec 64b double et long , car les écritures et les lectures sur ces types de données en Java ne sont pas atomic, et peut être fait en 2 opérations 32b . Cela peut avoir de très mauvaises conséquences.

Edit: Je viens de voir que chaque thread aura sa propre copie de l'objet. Dans ce cas, aucune synchronisation n'est nécessaire.


1 commentaires

Vous avez des problèmes flagrants avec les extraits de code fournis, parmi lesquels la faute d'orthographe de synchronized ainsi que l'exclusion de l'annotation @ .



0
votes

Thread Safe Class signifie que toutes les modifications (obtention / définition des valeurs) dans votre classe POJO sont effectuées Thread Safely .

Cela peut être réalisé par un mécanisme de synchronisation.

La solution générale est d'utiliser le mot-clé synchronisé sur les méthodes ou même sur tout objet privé logiquement utilisé à cette fin.

Ce mot-clé verrouille simplement l'objet et vous avez la garantie qu'un seul thread sera disponible pour accéder à cette méthode à un moment donné.

Mais la meilleure pratique (solution optimisée) est de réduire la section critique du code et de ne pas toujours utiliser synchronisé pour une solution simple / "rapide".


0 commentaires