和其他语言不同,Kotlin 只在标准库中提供最小化的低级 API 来工具化协程。和其他语言不同,async 和 await 在 Kotlin 中不是关键字,它们甚至都没出现在标准库中。Kotlin 的 suspending 函数概念提供了更加安全的、不易错的抽象用于异步操作,而不是 future 和 promise。

Jetbrains 开发的 kotlinx.coroutines 是一个用于丰富的协程库。它提供了很多用起来更加方便的高级携程 API,比如 launch、async 等。这里主要介绍这个库。

使用

gradle TODO:
maven TODO:

协程基础

在线程执行过程中开启一个协程

  1. import kotlinx.coroutines.*
  2. fun main() {
  3. GlobalScope.launch { // 开启一个新协程并继续
  4. delay(1000L) // 非阻塞延迟 1s
  5. println("World!") // 延迟后打印 world
  6. }
  7. println("Hello,") // 在协程延迟时,主线程正常执行
  8. Thread.sleep(2000L) // 主线程 sleep 2s 以确保 JVM 不立刻结束
  9. }

上面的代码,先立刻输出 Hello,1秒后输出 world,2秒后结束。
如果把第 9 行注释掉,上面的代码在输出 Hello 之后立刻就结束了。
协程是轻量级线程。上面的代码在 GlobalScope 中启动了一个新的协程,这意味着新协程的生存时间仅受限于整个应用程序的生存时间。

以阻塞方式执行协程

使用 runBlocking

  1. import kotlinx.coroutines.*
  2. fun main() {
  3. GlobalScope.launch { // 开启一个新协程并继续
  4. delay(1000L) // 非阻塞延迟 1s
  5. println("World!") // 延迟后打印 world
  6. }
  7. println("Hello,") // 在协程延迟时,主线程正常执行
  8. runBlocking {
  9. delay(2000L)
  10. }
  11. }

runBlocking 包装一个协程的执行为“同步操作”。执行 runBlocking 的线程会被阻塞,直到协程结束为止。

  1. runBlocking 时,主线程的状态是什么? TODO:
  2. 哪个线程在执行 runBlocking?TODO:

另外,runBlocking 可以返回一个结果:

  1. val v = runBlocking {
  2. delay(2000L)
  3. return@runBlocking 2234
  4. }
  5. println(v) // 输出 2234

在线程中等待 Job 执行完成

Global.launch 返回一个 Job。我们可以使用 Job api 来主动等任务完成:

  1. val job = GlobalScope.launch {
  2. delay(1000L)
  3. println("World!")
  4. }
  5. println("Hello,")
  6. job.join() // 等待协程完成