Kotlin `?.let` 是线程安全的吗?

Posted

技术标签:

【中文标题】Kotlin `?.let` 是线程安全的吗?【英文标题】:Is Kotlin `?.let` thread-safe? 【发布时间】:2019-12-10 22:42:06 【问题描述】:

Kotlin ?.let 线程安全吗?

假设a 变量可以在不同的线程中更改。 使用a?.let /* */ 线程安全吗?如果它等于if (a != null) block() ,会不会在if 中不为空而在block 中已经为空?

【问题讨论】:

我想如果让这个操作线程安全就太过分了 a 在块执行时可以为空,但it 不能。 IE。相当于val copy = a; if (copy != null) block(copy) @4ntoine 当 Kotlin 编译器智能地将可空类型转换为不可空类型时,您可以确定它确实是非空的。如果代码不是线程安全的,编译器会给你一个编译器错误(就像你这样做if (a != null) a.someFunction() 它会给你的编译器错误是这样的(如果aInt?类型):Smart cast to 'Int' is impossible, because 'a' is a mutable property that could have been changed by this time 【参考方案1】:

a?.let block() 确实等价于if (a != null) block()

这也意味着如果a是一个可变变量,那么:

    a 可能会在空检查后重新分配,并在执行block() 时保持null 值;

    所有与并发相关的效果都有效,如果a在线程之间共享以避免竞争条件,则需要正确同步;

但是,由于let ... 实际上将其接收者作为单个参数传递给它所接受的函数,它可以用于捕获a 的值并在 lambda 中使用它,而不是在 @ 中再次访问该属性987654330@。例如:

a?.let  notNullA -> block(notNullA) 

// with implicit parameter `it`, this is equivalent to:
a?.let  block(it) 

这里,作为参数传递给 lambda 的 a 的值保证与检查为 null 的值相同。但是,在 block() 中再次观察 a 可能会返回 null 或不同的值,并且观察给定实例的可变状态也应该正确同步。

【讨论】:

…而后一种情况线程安全的。 (从某种意义上说,let 参数始终与?. 检查的值相同,因此永远不能为空。但是,如果在此期间a 发生了变化,则不会反映这一点。 ) @gidds 这很有趣。有证据吗? 我认为它遵循 ?. 运算符的工作方式:它从表达式的左侧获取值(这可能意味着调用 getter 或其他),检查它是否为空,如果不是,对该值调用以下方法。在这种情况下,let() 然后将该值作为参数传递给函数。因此,在任何时候都没有机会获取不同的值。当然,如果值是一个可变对象,那么它的状态可以改变。但它必须是同一个对象。 @gidds,谢谢,我已经在答案中添加了关于它的评论。实际上,?. 只会访问该变量一次,如果返回值不为空,则调用该函数。 @AlexeyRomanov 我的陈述假定block 是无参数的,所以我会说它成立但不能解释?.let ... 的整个语义。谢谢你的评论!

以上是关于Kotlin `?.let` 是线程安全的吗?的主要内容,如果未能解决你的问题,请参考以下文章

HashMap是线程安全的吗?如何实现线程安全?

lua引擎本身是线程安全的吗

列表是线程安全的吗?

+= 运算符在 Python 中是线程安全的吗?

原子增加和比较是线程安全的吗

这段代码是线程安全的吗?