Я читал многопоточность на Java и наткнулся на это
Локальные переменные в Java являются потокобезопасными.
С тех пор я думал, как и почему локальные переменные являются потокобезопасными.
Может кто-нибудь дайте мне знать.
Я читал многопоточность на Java и наткнулся на это
Локальные переменные в Java являются потокобезопасными.
С тех пор я думал, как и почему локальные переменные являются потокобезопасными.
Может кто-нибудь дайте мне знать.
Ответы:
Когда вы создаете поток, он будет иметь свой собственный стек. Два потока будут иметь два стека, и один поток никогда не делит свой стек с другим потоком.
Всем локальным переменным, определенным в вашей программе, будет выделена память в стеке (как прокомментировал Джатин, память здесь означает ссылочное значение для объектов и значение для примитивных типов) (каждый вызов метода потоком создает кадр стека в своем собственном стеке). Как только выполнение метода будет завершено этим потоком, кадр стека будет удален.
На YouTube есть отличная лекция профессора Стэнфорда, которая может помочь вам понять эту концепцию.
Локальные переменные хранятся в собственном стеке каждого потока. Это означает, что локальные переменные никогда не используются совместно между потоками. Это также означает, что все локальные примитивные переменные являются потокобезопасными.
public void someMethod(){
long threadSafeInt = 0;
threadSafeInt++;
}
Локальные ссылки на объекты немного отличаются. Сама ссылка не передается. Однако указанный объект не сохраняется в локальном стеке каждого потока. Все объекты хранятся в общей куче. Если объект, созданный локально, никогда не ускользает от метода, в котором он был создан, он является потокобезопасным. Фактически, вы также можете передать его другим методам и объектам, если ни один из этих методов или объектов не сделает переданный объект доступным для других потоков.
Подумайте о методах как об определениях функциональности. Когда два потока выполняют один и тот же метод, они никоим образом не связаны. Каждый из них создаст свою собственную версию каждой локальной переменной и не сможет каким-либо образом взаимодействовать друг с другом.
Если переменные не являются локальными (например, переменные экземпляра, определенные вне метода на уровне класса), они прикрепляются к экземпляру (а не к отдельному запуску метода). В этом случае два потока, выполняющие один и тот же метод, видят одну переменную, и это не является потокобезопасным.
Рассмотрим эти два случая:
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;
}
}
В первом случае два потока, запущенные в одном экземпляре, NotThreadsafe
будут видеть один и тот же x. Это может быть опасно, потому что потоки пытаются изменить x! Во втором случае два потока, запущенные в одном экземпляре, Threadsafe
будут видеть совершенно разные переменные и не могут влиять друг на друга.
У каждого вызова метода есть свои собственные локальные переменные, и, очевидно, вызов метода происходит в одном потоке. Переменная, которая обновляется только одним потоком, по своей сути является потокобезопасной.
Однако внимательно следите за тем, что именно имеется в виду: только запись в саму переменную является потокобезопасной; Вызов методов объекта, на который он ссылается, по своей сути не является потокобезопасным . То же самое касается прямого обновления переменных объекта.
В дополнение к другим ответам, таким как Nambari's.
Хочу отметить, что вы можете использовать локальную переменную в методе анонимного типа:
Этот метод может быть вызван в других потоках, что может поставить под угрозу безопасность потоков, поэтому java заставляет все локальные переменные, используемые в анонимных типах, объявлять окончательными.
Рассмотрим этот незаконный код:
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();
}
}
Если бы Java действительно позволяла это (как это делает C # через «замыкания»), локальная переменная больше не будет потокобезопасной при любых обстоятельствах. В этом случае значение i
в конце всех потоков не гарантируется 100
.
У потока будет свой стек. Два потока будут иметь два стека, и один поток никогда не делит свой стек с другим потоком. Локальные переменные хранятся в собственном стеке каждого потока. Это означает, что локальные переменные никогда не используются совместно между потоками.
В основном в java есть четыре типа хранилища для хранения информации о классах и данных:
Область метода, куча, стек JAVA, ПК
Таким образом, область метода и куча совместно используются всеми потоками, но каждый поток имеет свой собственный стек JAVA и ПК, и он не используется другими потоками.
Каждый метод в java представляет собой фрейм стека. поэтому, когда один метод вызывается потоком, этот кадр стека загружается в его стек JAVA. Все локальные переменные, которые находятся в этом кадре стека и связанный стек операндов, не используются другими. ПК будет иметь информацию о следующей инструкции для выполнения в байтовом коде метода. поэтому все локальные переменные БЕЗОПАСНЫ ДЛЯ ПОТОКОВ.
@Weston также дал хороший ответ.
В стеке потока хранятся только локальные переменные.
Локальная переменная , которая является primitive type
(например , INT, долго ...) хранится на thread stack
и в результате - другой поток не имеет к нему доступ.
Локальная переменная , которая является reference type
(правопреемником Object
) содержит от 2 -х частей - адрес (который хранится на thread stack
) и объект (который хранится на 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;
}