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.
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.
Réponses:
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.
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
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 NotThreadsafe
verront 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 Threadsafe
verront des variables totalement différentes et ne pourront pas s'affecter.
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.
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
.
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.
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.
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;
}