为什么本地variables在Java中是安全的
我正在阅读Java中的multithreading,并且遇到了这个问题
Java中的局部variables是线程安全的。
从那以后,我一直在想如何/为什么局部variables是线程安全的。
有人可以让我知道。
当你创build一个线程时,它将创build自己的堆栈。 两个线程将有两个堆栈,一个线程从不与其他线程共享堆栈。
在你的程序中定义的所有局部variables将被分配内存堆栈(正如Jatin所述,这里的内存意味着对象的参考值和原始types的值)(每个线程的方法调用在它自己的堆栈上创build一个堆栈帧)。 一旦这个线程完成了方法执行,堆栈框架将被移除。
YouTube上的斯坦福教授做了很大的演讲,可以帮助你理解这个概念。
局部variables存储在每个线程自己的堆栈中。 这意味着线程之间永远不会共享局部variables。 这也意味着所有本地原始variables都是线程安全的。
public void someMethod(){ long threadSafeInt = 0; threadSafeInt++; }
对象的本地引用有点不同。 该参考本身不被共享。 然而,引用的对象并不存储在每个线程的本地堆栈中。 所有对象都存储在共享堆中。 如果在本地创build的对象永远不会转义它创build的方法,则它是线程安全的。 实际上,只要这些方法或对象都不会使传递的对象可用于其他线程,您也可以将它传递给其他方法和对象
想想function定义等方法。 当两个线程运行相同的方法时,它们绝不相关。 他们将各自创build自己的版本的每个局部variables,并将无法以任何方式互相交互。
如果variables不是本地的(就像在类级别的方法之外定义的实例variables),那么它们被附加到实例(而不是单次运行该方法)。 在这种情况下,运行同一个方法的两个线程都会看到一个variables,而这不是线程安全的。
考虑这两种情况:
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
实例上运行的两个线程将看到完全不同的variables,并且不会相互影响。
每个方法调用都有自己的局部variables,显然,一个方法调用发生在一个单独的线程中。 仅由单个线程更新的variables本质上是线程安全的。
但是 ,请密切注意这个意思是什么: 只有写入variables本身是线程安全的; 调用它所引用的对象上的方法本质上不是线程安全的 。 直接更新对象的variables也一样。
除了Nambari的其他答案。
我想指出的是,你可以使用一个局部variables在一个浮动types的方法:
这个方法可以在其他可能危及线程安全的线程中调用,所以java会强制所有用于dynamictypes的局部variables被声明为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#通过“闭包”一样),一个局部variables在任何情况下都不再是线程安全的。 在这种情况下,所有线程末尾的i
值不能保证为100
。
线程将有自己的堆栈。 两个线程将有两个堆栈,一个线程从不与其他线程共享堆栈。 局部variables存储在每个线程自己的堆栈中。 这意味着线程之间永远不会共享局部variables。
基本上四种types的存储在java中存储类信息和数据:
方法区,堆,JAVA堆栈,PC
所以方法区和堆被所有线程共享,但是每个线程都有自己的JAVA栈和PC,并且不被任何其他线程共享。
java中的每个方法都是作为Stack框架。 所以,当一个方法被一个线程调用时,堆栈框架被加载到它的JAVA栈上。所有在那个栈帧中的局部variables和相关的操作数堆栈都不被其他人所共享。 PC将在方法的字节码中有下一条指令的信息。 所以所有的局部variables都是线程安全的。
@韦斯顿也给出了很好的答案。