Kotlin局部变量线程安全

所以我正在编写一个单元测试来测试一些多线程,我想知道这个代码是否能保证按照我的预期工作。

fun testNumbers() { var firstNumber: Int? = null var secondNumber: Int? = null val startLatch = CountDownLatch(2) val exec = Executors.newFixedThreadPool(2) exec.submit({ startLatch.countDown() startLatch.await() firstNumber = StuffDoer.makeNumber() }) exec.submit({ startLatch.countDown() startLatch.await() secondNumber = StuffDoer().makeNumber() }) while (firstNumber == null || secondNumber == null) { Thread.sleep(1) } } 

具体来说,这个方法是否保证完成? firstNumbersecondNumber不是volatile那么这意味着exec线程中的那些值中设置的结果可能永远不会被运行测试的线程看到? 你不能将volatile应用到局部变量,所以实际上,如果可能有必要的话,你不能使函数局部变量变得不稳定。

(我把Java作为标签添加,因为大概Java的基本问题是相同的。)

使用Kotlin 1.1 RC编译器编译时,代码中的局部变量存储在ObjectRef ,然后在lambdas中使用。

您可以使用Kotlin字节码查看器来检查编译的代码片段。

ObjectRef将引用存储在非易失性字段中 ,因此不能保证程序完成。

Kotlin的早期版本曾经在Ref类中有一个volatile字段,但是这是一个没有记录的实现细节(即不是依赖的东西), 最终在Kotlin 1.1中被改变了。 看到这个线程的动机背后的非易失性捕获变量。


如问题描述中所述,

如果用户正在捕获一个变量并将其交给其他线程使用,那么就需要使用任何并发控制机制来建立读取和写入捕获的变量之间的相应的发生前边缘。 所有常规的并发机制,如开始/加入线程,创建期货等都是这样做的。

为了让您的示例程序正确同步,只需在从exec.submit { }返回的两个Future实例上调用.get()就足够了,因为Future提供了发生前保证:

Future发生的异步计算所采取的行为,在通过另一个线程中的Future.get()获取结果之后发生。

 val f1 = exec.submit { /* ... */ } val f2 = exec.submit { /* ... */ } f1.get() f2.get() // Both assignments made in the submitted tasks are visible now assert(firstNumber != null) assert(secondNumber != null)