我在用Java阅读多线程,碰到了这个问题
局部变量在Java中是线程安全的。
从那时起,我一直在思考局部变量如何/为什么是线程安全的。
有人可以让我知道吗。
Answers:
局部变量存储在每个线程自己的堆栈中。这意味着局部变量永远不会在线程之间共享。这也意味着所有本地原始变量都是线程安全的。
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的其他答案。
我想指出的是,您可以在匿名类型方法中使用局部变量:
可以在可能损害线程安全性的其他线程中调用此方法,因此java强制将用于匿名类型的所有局部变量声明为final。
考虑以下非法代码:
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#通过“ closures”所做的那样),则局部变量将不再在所有情况下都是线程安全的。在这种情况下,i
不能保证所有线程末尾的值是100
。
线程将拥有自己的堆栈。两个线程将具有两个堆栈,并且一个线程永远不会与其他线程共享其堆栈。局部变量存储在每个线程自己的堆栈中。这意味着局部变量永远不会在线程之间共享。
仅 局部变量存储在线程堆栈上。
局部变量是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;
}