上面的例子中,我们给出的是使用非阻塞的delay函数,同时又使用了阻塞的Thread.sleep函数,这样代码写在一起可读性不是那么地好。让我们来使用纯的Kotlin的协程代码来实现上面的 阻塞+非阻塞 的例子(不用Thread)。
9.2.1 runBlocking函数
Kotlin中提供了runBlocking函数来实现类似主协程的功能:
fun main(args: Array<String>) = runBlocking<Unit> {
// 主协程
println("${format(Date())}: T0")
// 启动主协程
launch(CommonPool) {
//在common thread pool中创建协程
println("${format(Date())}: T1")
delay(3000L)
println("${format(Date())}: T2 Hello,")
}
println("${format(Date())}: T3 World!") // 当子协程被delay,主协程仍然继续运行
delay(5000L)
println("${format(Date())}: T4")
}
运行结果:
14:37:59.640: T0
14:37:59.721: T1
14:37:59.721: T3 World!
14:38:02.763: T2 Hello,
14:38:04.738: T4
可以发现,运行结果跟之前的是一样的,但是我们没有使用Thread.sleep,我们只使用了非阻塞的delay函数。如果main函数不加 = runBlocking<Unit> , 那么我们是不能在main函数体内调用delay(5000L)的。如果这个阻塞的线程被中断,runBlocking抛出InterruptedException异常。
该runBlocking函数不是用来当作普通协程函数使用的,它的设计主要是用来桥接普通阻塞代码和挂起风格的(suspending style)的非阻塞代码的, 例如用在 main 函数中,或者用于测试用例代码中。
@RunWith(JUnit4::class)
class RunBlockingTest {
@Test fun testRunBlocking() = runBlocking<Unit> {
// 这样我们就可以在这里调用任何suspend fun了
launch(CommonPool) {
delay(3000L)
}
delay(5000L)
}
}