Les méthodes statiques non synchronisées sont-elles sûres pour les threads si elles ne modifient pas les variables de classe statiques?

145

Je me demandais si vous aviez une méthode statique qui n'est pas synchronisée, mais qui ne modifie aucune variable statique, est-elle thread-safe? Et si la méthode crée des variables locales à l'intérieur? Par exemple, le code suivant est-il thread-safe?

public static String[] makeStringArray( String a, String b ){
    return new String[]{ a, b };
}

Donc, si j'ai deux threads appelant cette méthode de manière continue et simultanée, l'un avec des chiens (disons "grand danois" et "bull dog") et l'autre avec des chats (disons "persan" et "siamois") aurai-je un jour des chats et des chiens dans le même tableau? Ou les chats et les chiens ne seront-ils jamais à l'intérieur de la même invocation de la méthode en même temps?

Traîneau
la source
un autre fil sur ce problème: stackoverflow.com/questions/8015797/…
象 嘉 道
2
C'est une question différente, c'est si l'appel de méthode statique est thread-safe, pas si les tableaux le sont.
Traîneau

Réponses:

212

Cette méthode est sûre à 100% pour les threads, même si ce n'était pas le cas static. Le problème de la sécurité des threads survient lorsque vous devez partager des données entre les threads - vous devez prendre soin de l'atomicité, de la visibilité, etc.

Cette méthode ne fonctionne que sur les paramètres, qui résident sur la pile et les références aux objets immuables sur le tas. La pile est intrinsèquement locale au thread , donc aucun partage de données ne se produit, jamais.

Les objets immuables ( Stringdans ce cas) sont également thread-safe car une fois créés, ils ne peuvent pas être modifiés et tous les threads voient la même valeur. D'un autre côté, si la méthode acceptait (mutable), Datevous auriez pu avoir un problème. Deux threads peuvent modifier simultanément cette même instance d'objet, provoquant des conditions de concurrence et des problèmes de visibilité.

Tomasz Nurkiewicz
la source
4
Bonne réponse. Les variables de niveau méthode sont répliquées dans chaque pile d'exécution de thread.
Sid
techniquement, la méthode doit être intégrée et les paramètres seront des registres CPU. Néanmoins, la réponse est correcte
bestsss
43
La pile est bien sûr locale au thread actuel, mais vous pouvez avoir des références à des objets partagés sur cette pile. Ce n'est pas un problème dans l'exemple car les chaînes sont immuables, mais une méthode qui modifie un paramètre passé peut avoir des problèmes de sécurité des threads si cet objet passé est accessible à partir de plusieurs threads.
Jörn Horstmann
1
Comme @TomaszNurkiewicz l'a mentionné, si nous passons une référence d'objet mutable, nous pouvons entrer dans des conditions de concurrence. Cela est-il vrai même si la méthode ne modifie en aucune façon l'objet? Je veux dire, sera-t-il toujours classé comme condition de course parce que l'objet était mutable? Et si nous ajoutions le mot-clé final aux paramètres?
Rafay
Que faire si je passe un objet de classe dans la méthode? Est-ce que le varaible dans la pile ou le tas?
grep
28

Une méthode ne peut être thread-unsafe que lorsqu'elle change un état partagé. Que ce soit statique ou non n'a pas d'importance.

Konrad Garus
la source
3
@Konrad_Garus La question ici était de savoir si les variables locales constituent un état partagé ou non, ou si la pile d'une méthode statique était par thread ou partagée.
Traîneau
"Une méthode ne peut être thread-unsafe que lorsqu'elle change un état partagé." Non, il peut également être dangereux pour les threads s'il accède simplement à l'état partagé sans le modifier. L'accès non synchronisé à un objet mutable peut accéder à un état incohérent si l'objet est muté par un autre thread, même si l'autre thread est correctement synchronisé. Les deux threads ont besoin d'une synchronisation appropriée pour que la sécurité des threads soit maintenue.
Warren Dew
12

La fonction est parfaitement thread-safe.

Si vous y réfléchissez ... supposez ce qui se passerait si c'était différent. Chaque fonction habituelle aurait des problèmes de thread si elle n'est pas synchronisée, donc toutes les fonctions API du JDK devraient être synchronisées, car elles pourraient potentiellement être appelées par plusieurs threads. Et comme l'application utilise la plupart du temps une API, les applications multithreads seraient effectivement impossibles.

C'est trop ridicule pour y penser, donc juste pour vous: les méthodes ne sont pas threadsafe s'il y a une raison claire pour laquelle il pourrait y avoir des problèmes. Essayez de toujours penser à ce qui se passe s'il y avait plusieurs threads dans ma fonction, et que se passerait-il si vous aviez un débogueur pas à pas et que vous aviez une étape après l'autre avancer le premier ... puis le deuxième thread ... peut-être le second encore ... y aurait-il des problèmes? Si vous en trouvez un, ce n'est pas thread-safe.

Veuillez également noter que la plupart des classes de la collection Java 1.5 ne sont pas threadsafe, à l'exception de celles indiquées, comme ConcurrentHashMap.

Et si vous voulez vraiment vous plonger dans cela, examinez de près le mot-clé volatile et TOUS ses effets secondaires. Jetez un œil à la classe Semaphore () et Lock () et à leurs amis dans java.util.Concurrent. Lisez tous les documents de l'API autour des classes. Cela vaut la peine d'apprendre et de satisfaire aussi.

Désolé pour cette réponse trop élaborée.

Daniel
la source
2
"Si vous y réfléchissez ... supposez ce qui se passerait si cela était différent. Chaque fonction habituelle aurait des problèmes de thread si elle n'était pas synchronisée, donc toutes les fonctions API du JDK devraient être synchronisées, car elles pourraient potentiellement être appelées par plusieurs fils. " Bon point!
Traîneau
1

Utilisez le staticmot - clé avec des méthodes statiques synchronisées pour modifier les données statiques partagées entre les threads. Avec le staticmot - clé, tous les threads créés se disputeront une seule version de la méthode.

L'utilisation du volatilemot - clé avec des méthodes d'instance synchronisées garantira que chaque thread a sa propre copie des données partagées et qu'aucune lecture / écriture ne s'échappera entre les threads.

Clinton
la source
0

Les objets String étant immuables est une autre raison du scénario thread-safe ci-dessus. Au lieu de cela, si des objets mutables sont utilisés (disons makeMutableArray ..), alors la sécurité des threads sera sûrement interrompue.

dur
la source
La question était de savoir si un appel de méthode statique verrait jamais les arguments d'un autre appel à la même méthode à partir d'un autre thread. La réponse est un «non!» Retentissant. Cela, je le savais mais je voulais pouvoir le prouver à des collègues douteux.
Traîneau du
Pourquoi cette réponse a-t-elle été votée à la baisse? Le point, non apporté par les autres réponses, est que la mutabilité peut être entrante ou sortante. Si vous renvoyez un mutable, vous n'êtes pas threadsafe. La question ne pose pas sa question aussi étroitement que le suggère le commentaire; la question étendue après l'exemple de code aurait pu être exprimée en code, peut-être sous forme de test unitaire. Mais je sympathise avec l'idée de convaincre des collègues. "Ils ne me croient pas, ni mon code de test, ni Josh Bloch, mais peut-être qu'ils accepteront une réponse sur SO."
som-snytt