Comportement de la méthode statique dans un environnement multithread en Java

114

Il y a une simple question stupide qui me dérange et qui fait plusieurs arguments dans mon esprit. Je veux jeter tous les doutes sur les questions ci-dessous.

class Clstest{

    public static String testStaticMethod(String inFileStr) {

        // section 0

        // section 1

        // do something with inFileStr

        // section 2

        // section 3

        return inFileStr;

    }

}

Supposons que cinq threads exécutent chacun un appel en Clstest.testStaticMethod("arg-n")même temps.

Thread 1 appelle Clstest.testStaticMethod("arg-1").

Lorsque le thread 1 est dans la section 1, le thread 2 appelle Clstest.testStaticMethod("arg-2").

Alors qu'arrivera-t-il au fil 1? Va-t-il s'endormir?

Quand Thread 1 aura-t-il la chance de reprendre l'exécution à partir de la section 1 où elle a été interrompue?

Comment cela se passe-t-il quand un seul Clstest.testStaticMethodet même Clstest.testStaticMethodest partagé entre les cinq threads?

Existe-t-il une possibilité d'échanger l' inFileStrenvoi par plusieurs threads?

Namalfernandolk
la source
Quelle langue ciblez-vous?
ΩmegaMan
3
@ OmegaMan: c'est java
namalfernandolk

Réponses:

192

La réponse de Hans Passant est bonne. Mais j'ai pensé que j'essaierais d'expliquer à un niveau légèrement plus simple pour quiconque rencontre cela et est nouveau sur Java. Voici..

La mémoire en java est divisée en deux types: le tas et les piles. Le tas est l'endroit où vivent tous les objets et les piles sont l'endroit où les threads font leur travail. Chaque thread a sa propre pile et ne peut pas accéder aux piles des autres. Chaque thread a également un pointeur dans le code qui pointe vers le bit de code en cours d'exécution.

Lorsqu'un thread commence à exécuter une nouvelle méthode, il enregistre les arguments et les variables locales de cette méthode sur sa propre pile. Certaines de ces valeurs peuvent être des pointeurs vers des objets sur le tas. Si deux threads exécutent la même méthode en même temps, ils auront tous les deux leurs pointeurs de code pointant vers cette méthode et auront leurs propres copies d'arguments et de variables locales sur leurs piles. Ils n'interféreront les uns avec les autres que si les objets de leurs piles pointent vers les mêmes objets sur le tas. Dans ce cas, toutes sortes de choses peuvent arriver. Mais comme Hans le fait remarquer, les chaînes sont immuables (ne peuvent pas être modifiées) donc nous sommes en sécurité si c'est le seul objet "partagé".

Tant de threads peuvent exécuter la même méthode. Ils peuvent ne pas s'exécuter en même temps - cela dépend du nombre de cœurs que vous avez sur votre machine car la JVM mappe les threads Java aux threads du système d'exploitation, qui sont planifiés sur les threads matériels. Vous avez donc peu de contrôle sur la façon dont ces threads s'entrelacent sans utiliser des mécanismes de synchronisation complexes .

Notez que dormir est quelque chose qu'un thread se fait.

selig
la source
3
Ainsi, dans un environnement de processeur multicœur, il peut y avoir plusieurs threads exécutant le même code en même temps, n'est-ce pas? Et dans un environnement à processeur unique, il n'y a qu'un seul thread à la fois. (plusieurs threads partageant le temps entre eux.) Ainsi, lorsque le thread Schedular donne la chance de passer le thread en cours d'exécution (A) au thread (B), comment le thread (A) reprend-il à partir de l'endroit où il a été mis en pause? Je veux dire comment connaît-il le point de reprise? Est-ce à cause de "Chaque thread a également un pointeur dans le code qui pointe vers le bit de code en cours d'exécution?" comme tu dis?
namalfernandolk
6
Vous l'avez. Juste pour clarifier certains points - premièrement, la façon dont les threads sont planifiés est hors du contrôle de Java. Je parle de la JVM Hotspot de Sun ici. La JVM mappe un thread Java à un thread du système d'exploitation et le système d'exploitation décide des threads à exécuter. Comme vous le dites, sur une machine à cœur unique, le système d'exploitation ne peut en exécuter qu'un à la fois, mais dans une machine multicœur, il peut en exécuter plusieurs à la fois. Deuxièmement, un thread n'est pas vraiment conscient du moment où il est mis en pause, les seules informations dont il dispose sont son pointeur de programme (le pointeur dans le code) et sa pile, qui sont enregistrés et restaurés exactement comme ils l'étaient.
selig le
Ainsi, l'interférence inter-thread se produit lorsque les threads utilisent des variables hors de leur portée locale et, par exemple, un thread met à jour la valeur de la variable avant qu'un autre thread tire cette variable (ou pointeur vers la variable) sur sa propre pile? Est-ce une bonne compréhension?
hariszhr
2
Pour être un peu plus précis ... les interférences ne peuvent se produire et peuvent se produire mais ne se produiront pas nécessairement ... lorsque les threads partagent des choses sur le tas (non local). Les interférences peuvent se produire de différentes manières, qui dépendent des dépendances entre les différentes parties du code. Je ne suis pas sûr de votre exemple car il manque certains détails. Vous faites peut-être référence à un problème potentiel où les threads A et B lisent tous deux une valeur partagée, puis la mettent à jour en fonction de la valeur lue. C'est une course aux données.
selig
1
@selig si j'ai une classe avec uniquement des méthodes d'instance par exemple: une classe de service et c'est singleton, je n'ai pas besoin de m'inquiéter de l'exécution des méthodes d'instance par plusieurs threads à la fois car la classe de service ne contient aucun état où state est présent uniquement si la classe a des variables d'instance. Ma compréhension est-elle correcte?
Yug Singh
67

Va-t-il s'endormir?

Non, l'exécution d'un thread n'affecte pas les autres threads tant qu'ils ne se synchronisent pas intentionnellement les uns avec les autres. Si vous avez plus d'un cœur de processeur, toutes les machines récentes le font, ces threads sont susceptibles de s'exécuter exactement au même moment. Cela devient un peu moins probable lorsque vous démarrez 5 threads car votre machine peut ne pas avoir assez de cœurs. Le système d'exploitation est obligé de choisir entre eux, leur donnant à chacun un certain temps pour s'exécuter. Le travail du planificateur de threads. Un thread ne sera alors pas dans un état "veille", il est simplement mis en pause et attend que le programmateur de threads lui donne une chance de s'exécuter. Il reprendra là où il a été interrompu par le planificateur.

Y a-t-il une possibilité d'échanger le inFileStr envoyé par plusieurs threads?

Une telle possibilité n'existe pas, les threads ont leur propre pile, donc tout argument de méthode et variable locale sera unique pour chaque thread. L'utilisation d'une chaîne garantit en outre que ces threads ne peuvent pas interférer les uns avec les autres car les chaînes sont immuables.

Il n'y a pas de telle garantie si l'argument est une référence à un autre type d'objet mutable. Ou si la méthode elle-même utilise des variables statiques ou des références à des objets sur le tas. La synchronisation est requise lorsqu'un thread modifie l'objet et qu'un autre thread le lit. Le mot clé lock dans le langage C # est le moyen standard d'implémenter une telle synchronisation requise. Le fait que la méthode soit statique ne signifie pas qu'une telle synchronisation n'est jamais nécessaire. Juste moins probable car vous n'avez pas à vous soucier des threads accédant au même objet (partageant cela ).

Hans Passant
la source
3
Oups, je n'ai jamais vu la balise [java]. Assez proche.
Hans Passant
J'ai oublié d'ajouter quand il a été publié. Ma faute. :). De toute façon merci pour la réponse. Cela a été très utile.
namalfernandolk