Scala 处理线程中的"sharing"局部变量与 Java 不同?它是如何工作的?



我对局部变量如何工作的心理模型是,它们存储在堆栈上,每个线程都有自己的堆栈,线程之间无法访问堆栈。

在Java中,我实际上不确定如何在派生线程中修改局部变量,因为编译器抱怨我无法在lambda或内部类中修改它。

然而,在Scala中,我可以做到这一点:

implicit val ec = scala.concurrent.ExecutionContext.global
var i = 5
val f = Future {
println((1, i))
i = 6
println((1, i))
}
val g = Future {
println((2, i))
println((2, i))
println((2, i))
}
Await.result(f, 3.seconds)

并获得的结果

(2,5)
(1,5)
(2,5)
(2,6)
(1,6)

线程#2如何看待线程#1的修改?

你说得很对。每个线程都有自己的堆栈,并且本地变量驻留在堆栈上。

这就是Java中局部变量应该是final或实际上是final的原因。但是,您可以使用一个众所周知的单元素数组技巧,这样指向数组的指针实际上是最终的,并驻留在堆栈上,但数组的元素可以在闭包中更改。像这样:

int a[] = new a[0];
Thread t = new Thread(() -> {
a[0] = 1;
});
//...

在Scala中,编译器为您制作类似的东西,并将它们放在堆中,而不是单独放在堆栈中。(很抱歉,不能写一个简单的Scala示例并立即查看它的字节码,但它非常简单,并且使用javap -c可读(

最新更新