一般我們需要異步操作的時候,都是通過多線程來實現的,但是線程的創建和開啓是個耗性能的操作,開少量的線程沒有問題,可是線程多了就有問題了,而且線程還會有各種數據同步的問題。
協程作爲一個輕量級的線程,可以完美解決這些問題。你試下開100萬個線程?不死機我吃電腦。但是你開100萬個協程,那是分分鐘的事。
這裏只說android
和kotlin
中的使用。
添加依賴
// kotlin 版本
ext.kotlin_version = '1.3.41'
// repository
jcenter()
// 依賴
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-RC2'
GlobalScope.launch
fun main() {
GlobalScope.launch {
println("我是一個協程")
delay(1000)
println("我不會打印,因爲主線程已經退出了")
}
// 和上面的代碼並行執行
Thread.sleep(500)
println("主線程退出了")
}
輸出:
我是一個協程
主線程退出了
runBlocking
fun main() {
runBlocking {
launch {
println("協程開始")
delay(1000)
println("協程結束")
}
}
// 會阻塞等待 runBlocking 中的代碼執行完畢
Thread.sleep(500)
println("主線程退出了")
}
輸出:
協程開始
協程結束
主線程退出了
suspend
fun main() {
runBlocking {
println("開始")
launch {
test()
}
println("結束")
}
}
suspend fun test() {
delay(1000L)
println("我是suspend方法打印的")
}
輸出:
開始
結束
我是suspend方法打印的
Job
fun main() {
runBlocking {
println("開始")
val job = launch {
delay(1000L)
println("in launch")
}
job.join()
println("結束")
}
}
輸出:
開始
in launch
結束
cancelAndJoin
Job.cancel 實際上是拋出異常,會直接中斷執行。
fun main() {
runBlocking {
println("開始")
val job = launch {
try {
var i = 1
while (isActive) {
print(i++)
delay(500L)
}
} finally {
println("\n異常退出")
}
}
delay(1300L)
job.cancelAndJoin()// cancel實質上是拋出異常,所以會直接停止,而不會等到delay完後再停止
println("結束")
}
}
輸出:
開始
123
異常退出
結束
withTimeout
Timeout
實際上也是拋出異常。
fun main() {
runBlocking {
println("開始")
try {
val result = withTimeout(1300) {
repeat(10) {
print(it)
delay(500)
}
"正常完成,沒有Timeout"
}
println("\n結束 result=$result")
} catch (e: TimeoutCancellationException) {
println("\n結束 Timeout了")
}
}
}
輸出:
開始
012
結束 Timeout了
Channel
Channel
相當於BlockingQueue
fun main() {
runBlocking {
println("開始")
val channel = Channel<Int>()
launch {
for (x in 1..5) channel.send(x * x)
channel.close()
}
for (y in channel) print("$y ")
println("\n結束")
}
}
輸出:
開始
1 4 9 16 25
結束
async、await
fun main() {
runBlocking {
println("開始")
val d = async {
println("async start...")
delay(1000)
println("async end")
999
}
println("d=${d.await()}")
println("結束")
}
}
如果想要 async
不自行執行,加上 CoroutineStart.LAZY
即可,然後 async
將會等待調用 start
或者 await
後纔會執行,如下:
fun main() {
runBlocking {
println("開始")
val d = async(start = CoroutineStart.LAZY) {
println("async start...")
delay(1000)
println("async end")
999
}
d.start()
println("d=${d.await()}")
println("結束")
}
}
輸出:
開始
async start…
async end
d=999
結束
真正執行線程
fun main() {
runBlocking {
// 默認執行在當前線程
launch {
println("launch\t\t\t\t\t" + Thread.currentThread().name)
}
// 默認執行在工作線程
GlobalScope.launch {
println("GlobalScope.launch\t\t" + Thread.currentThread().name)
}
// 默認執行在工作線程
launch(Dispatchers.Default) {
println("Dispatchers.Default\t\t" + Thread.currentThread().name)
}
// 默認執行在工作線程
launch(Dispatchers.IO) {
println("Dispatchers.IO\t\t\t" + Thread.currentThread().name)
}
// 不限制的,可能執行在任何線程,甚至裏面的不同行代碼也會執行在不同的線程
launch(Dispatchers.Unconfined) {
println("Dispatchers.Unconfined\t" + Thread.currentThread().name)
}
// 只有android中才能用main
// launch(Dispatchers.Main) {
// println("Dispatchers.Main\t\t" + Thread.currentThread().name)
// }
}
}
輸出:
GlobalScope.launch DefaultDispatcher-worker-1
Dispatchers.Default DefaultDispatcher-worker-3
Dispatchers.IO DefaultDispatcher-worker-3
Dispatchers.Unconfined main
launch main
官方文檔
https://kotlinlang.org/docs/reference/coroutines/coroutines-guide.html
https://github.com/Kotlin/kotlinx.coroutines