【问题标题】:Is Kotlin `?.let` thread-safe?Kotlin `?.let` 是线程安全的吗?
【发布时间】: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

标签: multithreading kotlin let thread-synchronization


【解决方案1】:

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

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

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

  2. 所有与并发相关的效果都有效,如果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 { ... } 的整个语义。谢谢你的评论!
猜你喜欢
  • 1970-01-01
  • 2022-06-15
  • 1970-01-01
  • 2021-10-12
  • 2015-04-18
  • 2011-10-07
  • 2012-03-02
  • 2011-10-28
  • 2023-03-14
相关资源
最近更新 更多