開發環境

  • IntelliJ IDEA 2021.2.2 (Community Edition)
  • Kotlin: 212-1.5.10-release-IJ5284.40

介紹Kotlin中的協程。用一個例子來展示協程的基本用法。

第一個例子

新建工程

我們使用的是社群版IntelliJ IDEA 2021.2.2。新建一個Kotlin工程用來測試。

引入協程

專案用gradle進行管理,我們在Github上找到協程的依賴。

dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
}

修改專案的gradle配置。把依賴新增進去。

程式碼示例

建立一個類然後在main方法中寫協程的相關程式碼。

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch fun main() {
GlobalScope.launch { // 在後臺啟動一個新的協程並繼續
delay(300) // 等待300毫秒
"rustfisher.com".forEach {
print(it)
delay(200) // 每次列印都等待一下
}
}
println("RustFisher")
Thread.sleep(3000) // 阻塞主執行緒防止過快退出
}

程式碼執行結果

本質上,協程是輕量級的執行緒。

我們用GlobalScope啟動了一個新的協程,這意味著新協程的生命週期只受整個應用程式的生命週期限制。

可以將 GlobalScope.launch { …… } 替換為 thread { …… },並將 delay(……) 替換為 Thread.sleep(……) 達到同樣目的。注意匯入包kotlin.concurrent.thread

協程換成執行緒

    import java.lang.Thread.sleep
import kotlin.concurrent.thread fun main() {
thread {
sleep(300)
"rustfisher.com".forEach {
print(it)
sleep(200)
}
}
println("RustFisher")
sleep(3000) // 阻塞主執行緒防止過快退出
}

如果thread{}中含有delay,編譯器會報錯

Suspend function 'delay' should be called only from a coroutine or another suspend function

因為delay是一個特殊的掛起函式,它不會造成執行緒阻塞,但是會掛起協程,並且只能在協程中使用。

至此,小結一下第一個協程示例

  • gradle引入協程kotlinx-coroutines-core
  • GlobalScope.launch啟動協程
  • 協程中的掛起函式delay(long)可以達到延時的效果,並且它只能在協程中使用

協程所線上程

本質上協程是輕量級的執行緒。我們觀察一下協程所處的執行緒資訊。

    import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.lang.Thread.sleep fun main() {
println("main執行緒資訊 ${Thread.currentThread().id}")
for (i in 1..3) { // 多啟動幾次協程
GlobalScope.launch {
println("協程啟動#$i 所線上程id: ${Thread.currentThread().id}")
}
}
sleep(2000) // 阻塞主執行緒防止過快退出
println("RustFisher 示例結束")
}

執行log如下

   main執行緒資訊 1
協程啟動#1 所線上程id: 11
協程啟動#3 所線上程id: 14
協程啟動#2 所線上程id: 13
RustFisher 示例結束

可以看到多次啟動協程,這些協程它們不一定在同一個執行緒中。也就是說有在同一個執行緒的可能性。

於是試試瘋狂地啟動協程,把迴圈次數加大for (i in 1..3000)。觀察log可以看出,有重複的執行緒id。