为什么.let可以防止多线程中的nullPointException?

1 kotlin

我们知道,全局变量的值可以随时被其他线程修改。但是为什么?.letkotlin 可以防止多线程中的 NPE 呢?例如:

   var demo : Demo? = null
    demo = Demo()
    Thread{
        demo?.let {
            while (true){
                it.run()
                Thread.sleep(300)
            }
        }
    }.start()
    Thread.sleep(3000)
    demo = null
Run Code Online (Sandbox Code Playgroud)

上面的程序中,虽然主线程将变量设置demo为null,但子线程仍能正常执行。

那么,为什么“let”构造中的“it”不能受到其他线程的影响呢?它是对象“演示”的深层副本吗?

Jof*_*rey 7

那么,为什么“let”构造中的“it”不能被其他线程影响呢?

.let { }确实没有什么神奇的。这是一个非常简单的功能。当您编写 时demo?.let { println(it) },代码实际上相当于:

val it = demo
if (it != null) {
    println(it)
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,创建了一个新变量并将其值设置为demo。因此,如果其他线程修改demoit不受影响。

这是对象“演示”的深层副本?

它实际上不是深层复制:如果线程改变了实例的属性Demo,则访问该实例*的任何代码都可以看到它们,甚至通过变量也是如此it

但是,您不需要深复制此代码即可正常工作。demo是一个引用变量,最初指向Demo()代码开头创建的实例。

当我们这样做时val it = demo(从相当于 的代码?.let),我们将变量的当前值复制demo到 中it,并且该值是对该实例的引用Demo。我们说it“指向”与 相同的Demo实例demo

当另一个线程设置demo为时null,它不会更改Demo实例中的任何内容。其效果是,现在demo不再指向初始Demo实例。但it还是指出了这一点。

(*虽然这里有一些微妙之处,比如先发生关系、易失变量等,但我们不要让事情复杂化)