9.2 桥接 阻塞和非阻塞

上面的例子中,我们给出的是使用非阻塞的delay函数,同时又使用了阻塞的Thread.sleep函数,这样代码写在一起可读性不是那么地好。让我们来使用纯的Kotlin的协程代码来实现上面的 阻塞+非阻塞 的例子(不用Thread)。

9.2.1 runBlocking函数

Kotlin中提供了runBlocking函数来实现类似主协程的功能:

  1. fun main(args: Array<String>) = runBlocking<Unit> {
  2. // 主协程
  3. println("${format(Date())}: T0")
  4. // 启动主协程
  5. launch(CommonPool) {
  6. //在common thread pool中创建协程
  7. println("${format(Date())}: T1")
  8. delay(3000L)
  9. println("${format(Date())}: T2 Hello,")
  10. }
  11. println("${format(Date())}: T3 World!") // 当子协程被delay,主协程仍然继续运行
  12. delay(5000L)
  13. println("${format(Date())}: T4")
  14. }

运行结果:

  1. 14:37:59.640: T0
  2. 14:37:59.721: T1
  3. 14:37:59.721: T3 World!
  4. 14:38:02.763: T2 Hello,
  5. 14:38:04.738: T4

可以发现,运行结果跟之前的是一样的,但是我们没有使用Thread.sleep,我们只使用了非阻塞的delay函数。如果main函数不加 = runBlocking<Unit> , 那么我们是不能在main函数体内调用delay(5000L)的。

如果这个阻塞的线程被中断,runBlocking抛出InterruptedException异常。

该runBlocking函数不是用来当作普通协程函数使用的,它的设计主要是用来桥接普通阻塞代码和挂起风格的(suspending style)的非阻塞代码的, 例如用在 main 函数中,或者用于测试用例代码中。

  1. @RunWith(JUnit4::class)
  2. class RunBlockingTest {
  3. @Test fun testRunBlocking() = runBlocking<Unit> {
  4. // 这样我们就可以在这里调用任何suspend fun了
  5. launch(CommonPool) {
  6. delay(3000L)
  7. }
  8. delay(5000L)
  9. }
  10. }