因此,我正在编写用于测试某些多线程的单元测试,并且我想知道该代码是否可以保证按预期工作。
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)
}
}
具体来说,此方法是否可以保证完成?firstNumber
而secondNumber
不是volatile
这是否意味着从这些值设定的结果exec
线程可能永远不会通过运行测试的线程可以看到?您不能将volatile应用于局部变量,因此实际上来说,如果有必要,就不能使函数局部变量变为volatile对我来说没有意义。
(我添加了Java作为标记,因为大概的基本问题在Java中是相同的。)
使用Kotlin 1.1 RC编译器进行编译时,代码中的局部变量存储在ObjectRef
s中,然后在lambda中使用。
您可以使用Kotlin字节码查看器检查要编译的代码段。
ObjectRef
将引用存储在非易失性字段中,因此实际上不能保证程序会完成。
早期版本的Kotlin曾经volatile
在Ref
类中包含一个字段,但这是一个未记录的实现细节(即不是要依赖的东西),最终在Kotlin 1.1中进行了更改。有关非易失性捕获变量的动机,请参见此线程。
如问题描述中所述,
如果用户正在捕获变量并将其交给其他线程使用,则需要使用任何并发控制机制来建立相应的事件,即在读取和写入捕获的变量之间的边沿之前。所有常规的并发机制,例如启动/加入线程,创建期货等。
为了使示例程序正确同步,只需调用从返回.get()
的两个Future
实例就足够了exec.submit { }
,因为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)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句