如图所示, 位置 2 和位置3 为什么可以访问 位置1 (也就是主线程)的 point 局部变量 ?
毕竟 位置 2 和位置3 是另外两个线程啊 !!
当我加上 第10行代码后,thread1 和 thead2 中都不能访问主线程中的point 了。我知道这是内部类的“事实最终变量” 的限制。
如下图所示,就是我不理解的地方。(在 “栈内存” 层面)
我的猜测:之所以 thread1 和 tread2 这两个新的线程并没有初始化 point 这个变量 但是还能使用的原因是因为 Runnable 的两个实现类 内部都各自 生成了一个 point 实例变量 ? (虽然书上的解释是针对局部内部类,针对外面的方法执行完毕局部变量就不复存在的原因, 但是我不知道 多线程 能不能也可以同样这样解释)。
在Java中,多线程访问局部变量的问题涉及到线程的可见性和内存模型。
在你提供的代码中,位置1的point变量是在主线程中声明的局部变量。通常情况下,每个线程都有自己的线程栈,线程栈中包含了线程执行过程中所使用的局部变量。对于主线程而言,point是它的局部变量,而对于线程thread1和thread2而言,它们也有各自的线程栈,理论上是无法直接访问主线程的局部变量的。
然而,在Java中,有一个特例,就是匿名内部类和Lambda表达式对外部局部变量的访问。这种访问方式实际上是通过将外部的局部变量复制一份到内部类的实例变量中,从而实现对外部局部变量的访问。这样,即使外部方法执行完毕,局部变量仍然存在于内部类的实例中。
在你的代码中,如果没有第10行的Thread.sleep(2000),主线程在执行完point++后很快就结束了,但由于thread1和thread2在使用point的时候仍然处于活动状态,它们能够访问到被复制到内部类实例变量中的point。
当你加上第10行的Thread.sleep(2000)后,主线程休眠了2秒钟,此时thread1和thread2可能已经执行完了,导致它们内部类实例中的point变量被销毁,因此在之后的System.out.println(point)处会出现编译错误。
在多线程编程中,要特别小心共享变量的访问,可以使用volatile关键字、synchronized关键字或者使用java.util.concurrent包中的工具来保证线程安全。
兄弟,你是机器人吧
“第10行的Thread.sleep(2000)” ?? 哪里有 Thread.sleep(2000) ???
可以了解一下字节码相关知识,一般这种情况看一下字节码就比较清楚了。
1、匿名类会单独生成一个class以及对应的.class文件
2、通过查看原始文件Test.class和匿名类文件Test$1.class的字节码。
可以看到:
2.1、匿名类Test$1中定义了一个Point的私有变量;
2.2、匿名类定义了一个包含Point类参数的构造函数,在构造函数中将入参的Point对象赋值给了私有变量;
2.3、在Test类中将局部变量point赋值到了Test$1的构造函数中;
由以上分析可以得出,Runnable匿名类中,直接使用了局部变量创建的对象。
我滴图图呢?
– realzhangsan 11个月前