Pourquoi les variables locales sont-elles thread-safe en Java

90

Je lisais du multi-threading en Java et je tombe sur ceci

Les variables locales sont thread-safe en Java.

Depuis, je me suis demandé comment / pourquoi les variables locales sont thread-safe.

Quelqu'un peut-il me le faire savoir.

Anand
la source
27
Parce qu'ils sont alloués dans Stack. Et les threads ne partagent pas la pile .. son unique pour chacun ..
Rohit Jain

Réponses:

103

Lorsque vous créez un thread, sa propre pile sera créée. Deux threads auront deux piles et un thread ne partage jamais sa pile avec un autre thread.

Toutes les variables locales définies dans votre programme se verront allouer de la mémoire dans la pile (comme Jatin l'a commenté, la mémoire signifie ici, valeur de référence pour les objets et valeur pour les types primitifs) (Chaque appel de méthode par un thread crée un cadre de pile sur sa propre pile). Dès que l'exécution de la méthode est terminée par ce thread, le cadre de la pile sera supprimé.

Il y a une excellente conférence du professeur de Stanford sur YouTube qui peut vous aider à comprendre ce concept.

kosa
la source
13
Je suis désolé, vous vous trompez, seules les variables locales primitives sont stockées sur la pile. Reste toutes les variables sont stockées sur Heap. Java 7 a introduit l'analyse d'échappement, qui pour certaines variables pourrait l'allouer dans la pile
Jatin
6
Stack contient uniquement la référence à l'objet sur le tas. Parce que la pile est effacée, la référence fait de même. par conséquent, il est disponible pour la collecte des ordures
Jatin
6
@Jatin: Vous avez raison. Quand je veux dire mémoire, je veux dire valeur de référence pour les objets et valeurs pour les primitives (je pense que les développeurs novices savent également que les objets sont sur le tas).
kosa
2
@Nambari mais si la valeur de référence pointe vers une variable partagée. Alors, comment pouvons-nous dire qu'il est thread-safe?
H.Rabiee
3
@hajder: Qu'est-ce qui fait qu'une variable est partagée? commencer à partir de là. Soit des variables d'instance ou de classe, non? pas des variables locales ET lire la réponse de Marko Toplink dans ce fil, je pense que c'est le point sur lequel vous êtes confus.
kosa
19

Les variables locales sont stockées dans la propre pile de chaque thread. Cela signifie que les variables locales ne sont jamais partagées entre les threads. Cela signifie également que toutes les variables primitives locales sont thread-safe.

public void someMethod(){

   long threadSafeInt = 0;

   threadSafeInt++;
}

Les références locales aux objets sont un peu différentes. La référence elle-même n'est pas partagée. L'objet référencé n'est cependant pas stocké dans la pile locale de chaque thread. Tous les objets sont stockés dans le tas partagé. Si un objet créé localement n'échappe jamais à la méthode dans laquelle il a été créé, il est thread-safe. En fait, vous pouvez également le transmettre à d'autres méthodes et objets tant qu'aucune de ces méthodes ou objets ne rend l'objet passé disponible à d'autres threads

Renjith
la source
Il y a une erreur d'agrément, veuillez consulter les commentaires de la réponse @Nambari
Jatin
Si vous pointez sur le fait que localSafeInt sera toujours juste 0, puis 1, puis supprimé de toute façon, c'est bien. Donc, cela montre que cette variable n'est pas partagée entre les threads et donc pas affectée par le multi threading .. je pense que vous pourriez le souligner un peu plus que threadsafe est toujours juste 0 ou 1
tObi
14

Pensez à des méthodes telles que les définitions de la fonctionnalité. Lorsque deux threads exécutent la même méthode, ils ne sont en aucun cas liés. Ils créeront chacun leur propre version de chaque variable locale et ne pourront en aucun cas interagir les uns avec les autres.

Si les variables ne sont pas locales (comme les variables d'instance définies en dehors d'une méthode au niveau de la classe), elles sont alors attachées à l'instance (pas à une seule exécution de la méthode). Dans ce cas, deux threads exécutant la même méthode voient tous deux la seule variable, et ce n'est pas thread-safe.

Considérez ces deux cas:

public class NotThreadsafe {
    int x = 0;
    public int incrementX() {
        x++;
        return x;
    }
}

public class Threadsafe {
    public int getTwoTimesTwo() {
        int x = 1;
        x++;
        return x*x;
    }
}

Dans le premier, deux threads s'exécutant sur la même instance de NotThreadsafeverront le même x. Cela peut être dangereux, car les threads essaient de changer x! Dans le second, deux threads s'exécutant sur la même instance de Threadsafeverront des variables totalement différentes et ne pourront pas s'affecter.

Cory Kendall
la source
6

Chaque appel de méthode a ses propres variables locales et, évidemment, un appel de méthode se produit dans un seul thread. Une variable qui n'est mise à jour que par un seul thread est intrinsèquement thread-safe.

Cependant , gardez un œil attentif sur ce que cela signifie exactement: seules les écritures dans la variable elle-même sont thread-safe; l'appel de méthodes sur l'objet auquel il fait référence n'est pas intrinsèquement thread-safe . Il en va de même pour la mise à jour directe des variables de l'objet.

Marko Topolnik
la source
1
Vous dites "appeler des méthodes sur l'objet auquel il fait référence n'est pas intrinsèquement thread-safe". Mais, comment l'objet référencé par une référence locale de méthode - instancié dans cette portée de méthode - peut être partagé par deux threads? Pourriez-vous nous indiquer par exemple?
Akshay Lokur
1
Une variable locale peut ou non contenir un objet instancié dans la portée de la méthode, qui ne faisait pas partie de la question. Même si c'est le cas, la méthode peut accéder à l'état partagé.
Marko Topolnik
6

En plus des autres réponses telles que celle de Nambari.

Je tiens à souligner que vous pouvez utiliser une variable locale dans une méthode de type anoymous:

Cette méthode pourrait être appelée dans d'autres threads, ce qui pourrait compromettre la sécurité des threads, donc java force toutes les variables locales utilisées dans un autre type à être déclarées comme finales.

Considérez ce code illégal:

public void nonCompilableMethod() {
    int i=0;
    for(int t=0; t<100; t++)
    {
      new Thread(new Runnable() {
                    public void run() {
                      i++; //compile error, i must be final:
                      //Cannot refer to a non-final variable i inside an
                      //inner class defined in a different method
                    }
       }).start();
     }
  }

Si java le permettait (comme le fait C # via des "fermetures"), une variable locale ne serait plus threadsafe dans toutes les circonstances. Dans ce cas, la valeur de ià la fin de tous les threads n'est pas garantie 100.

Weston
la source
Bonjour Weston, D'après la discussion ci-dessus et les réponses ci-dessous, j'ai compris que java assure la sécurité des threads pour toutes les variables locales. Puis-je savoir quelle est l'utilisation réelle du mot-clé synchronisé alors? pourriez-vous s'il vous plaît expliquer avec un exemple comme celui-ci.
Prabhu
5

Thread aura sa propre pile. Deux threads auront deux piles et un thread ne partage jamais sa pile avec un autre thread. Les variables locales sont stockées dans la propre pile de chaque thread. Cela signifie que les variables locales ne sont jamais partagées entre les threads.

Sudhirkumar Murkute
la source
3

Fondamentalement, quatre types de stockage sont disponibles en Java pour stocker les informations et les données de classe:

Zone de méthode, tas, pile JAVA, PC

Ainsi, la zone de méthode et le tas sont partagés par tous les threads, mais chaque thread a sa propre pile JAVA et son propre PC et qui ne sont partagés par aucun autre thread.

Chaque méthode en java est en tant que cadre de pile. Ainsi, lorsqu'une méthode est appelée par un thread, ce cadre de pile est chargé sur sa pile JAVA.Toutes les variables locales qui se trouvent dans ce cadre de pile et la pile d'opérandes associée ne sont pas partagées par d'autres. Le PC aura des informations sur la prochaine instruction à exécuter dans le code d'octet de la méthode. donc toutes les variables locales sont THREAD SAFE.

@Weston a également donné une bonne réponse.

Prashant
la source
1

Seules les variables locales sont stockées sur la pile de threads.

La variable locale qui est primitive type(par exemple int, long ...) est stockée sur lethread stack et par conséquent - les autres threads n'y ont pas accès.

La variable locale qui est reference type(successeur de Object) contient à partir de 2 parties - l'adresse (qui est stockée sur thread stack) et l'objet (qui est stocké sur heap)


class MyRunnable implements Runnable() {
    public void run() {
        method1();
    }

    void method1() {
        int intPrimitive = 1;

        method2();
    }

    void method2() {
        MyObject1 myObject1 = new MyObject1();
    }
}

class MyObject1 {
    MyObject2 myObject2 = new MyObject2();
}

class MyObject2 {
    MyObject3 myObject3 = MyObject3.shared;
}

class MyObject3 {
    static MyObject3 shared = new MyObject3();

    boolean b = false;
}

entrez la description de l'image ici

yoAlex5
la source