Existe-t-il un moyen général ou des règles permettant de garantir la sécurité des threads des méthodes statiques spécifiquement utilisées dans les différentes classes utilitaires de toutes les applications? Ici, je tiens à souligner spécifiquement la sécurité des threads des applications Web.
Il est bien connu que les méthodes statiques avec des objets immuables en tant que paramètres sont thread-safe et les objets Mutable ne le sont pas.
Si j'ai une méthode utilitaire pour une certaine manipulation de Java.util.Date
et cette méthode accepte une instance de Java.util.Date
, alors cette méthode ne serait pas thread-safe. Alors, comment le rendre sûr pour les threads sans changer la façon de passer les paramètres?
public class DateUtils {
public static Date getNormalizeDate(Date date) {
// some operations
}
}
Est également la classe javax.faces.context.FacesContext
mutable? Le thread est-il sûr de passer une instance de cette classe à une telle méthode utilitaire statique?
Cette liste de classes, dont les instances peuvent être ou ne peuvent pas être passées en tant que paramètres, peut être longue; alors quels points faut-il garder à l'esprit lors de l'écriture des codes de ces classes d'utilité?
Il est bien connu que les méthodes statiques avec des objets immuables comme paramètres sont thread-safe et les objets mutables ne le sont pas.
Je contesterais cela. Les arguments passés à une méthode sont stockés sur une pile, qui est un idiome par thread.
Si votre paramètre est un objet modifiable tel qu'un Date
, vous devez vous assurer que les autres threads ne le modifient pas en même temps ailleurs. Mais c'est une question différente sans rapport avec la sécurité des threads de votre méthode.
La méthode que vous avez publiée est thread-safe. Il ne maintient aucun état et ne fonctionne que sur ses arguments.
Je vous recommande fortement de lire Java Concurrency in Practice , ou un livre similaire dédié à la sécurité des threads en Java. C'est un sujet complexe qui ne peut pas être abordé de manière appropriée à travers quelques réponses StackOverflow.
Puisque votre classe ne contient aucune variable membre, votre méthode est sans état (elle utilise uniquement des variables locales et l'argument) et est donc thread-safe.
Le code qui l'appelle n'est peut-être pas thread-safe mais c'est une autre discussion. Par exemple, la date n'étant pas sécurisée pour les threads, si le code appelant lit une date qui a été écrite par un autre thread, vous devez utiliser une synchronisation appropriée dans le code d'écriture et de lecture de la date.
Compte tenu de la structure de la JVM, les variables locales, les paramètres de méthode et les valeurs de retour sont intrinsèquement "thread-safe". Mais les variables d'instance et les variables de classe ne seront thread-safe que si vous concevez votre classe de manière appropriée. plus ici
Voici comment j'y pense: imaginez un CampSite (c'est une méthode statique). En tant que campeur, je peux apporter un tas d'objets dans mon sac à dos (c'est des arguments passés sur la pile). Le CampSite me fournit un endroit pour mettre ma tente et mon réchaud, etc., mais si la seule chose que fait le CampSite est de me permettre de modifier mes propres objets, alors c'est threadsafe. Le CampSite peut même créer des choses à partir de rien (FirePit firepit = new FirePit();
), qui sont également créées sur la pile.
À tout moment, je peux disparaître avec tous mes objets dans mon sac à dos et l'un des autres campeurs peut apparaître, faisant exactement ce qu'ils faisaient la dernière fois qu'ils ont disparu. Différents threads de ce CampSite n'auront pas accès aux objets de la pile créée CampSite dans d'autres threads.
Disons qu'il n'y a qu'un seul campStove (un seul objet de CampStove, pas des instanciations séparées). Si, par un effort d'imagination, je partage un objet CampStove, il y a des considérations de multi-threading. Je ne veux pas allumer mon réchaud de camping, disparaître puis réapparaître après qu'un autre campeur l'ait éteint - je vérifierais toujours si mon hot dog a été fait et il ne le sera jamais. Il faudrait mettre une synchronisation quelque part ... dans la classe CampStove, dans la méthode qui appelait le CampSite, ou dans le CampSite lui-même ... mais comme Duncan Jones dit, "c'est un autre matière".
Notez que même si nous campions dans des instanciations distinctes d'objets non - statiques CampSite, le partage d'un campStove aurait les mêmes considérations multi-threading.
Je recommanderais de créer une copie de cet objet (modifiable) dès que la méthode démarre et d'utiliser la copie au lieu du paramètre d'origine.
Quelque chose comme ça
public static Date getNormalizeDate(Date date) {
Date input = new Date(date.getTime());
// ...
}
Je vois beaucoup de réponses mais aucune n'en indique vraiment la raison.
Donc, cela peut être pensé comme ceci, chaque fois qu'un thread est créé, il est créé avec sa propre pile (je suppose que la taille de la pile au moment de la création est ~ 2 Mo). Donc, toute exécution qui se produit se produit réellement dans le contexte de cette pile de threads. Toute variable qui est créée vit dans le tas, mais c'est la vie de référence dans la pile, à l'exception des variables statiques qui ne vivent pas dans la pile de threads.
Tout appel de fonction que vous effectuez est en fait poussé sur la pile de threads, qu'il soit statique ou non statique. Étant donné que la méthode complète a été poussée sur la pile, toute création de variable qui a lieu vit dans la pile (à nouveau les exceptions étant des variables statiques) et n'est accessible qu'à un seul thread.
Toutes les méthodes sont donc thread-safe jusqu'à ce qu'elles changent l'état d'une variable statique.