我們要說(shuō)明一下,這里的實(shí)例分析并不會(huì)去分析協(xié)程的源碼,所以說(shuō)這個(gè)是個(gè)使用層面的分析。因?yàn)槲冶緛?lái)就是個(gè)使用者,不太關(guān)心它是怎么實(shí)現(xiàn)的, 我們此次要進(jìn)一步了解協(xié)程的執(zhí)行順序,調(diào)度原理,還是先出題,說(shuō)出下面實(shí)例的輸出順序,如能說(shuō)出代表你對(duì)協(xié)程已經(jīng)達(dá)到入門級(jí),不能的話看第一個(gè)實(shí)例
package com.cro.test
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
println("launch1 started ${Thread.currentThread().name}")
delay(3000)
println("launch1 ended ${Thread.currentThread().name}")
}
launch(Dispatchers.Default){
println("launch2 started ${Thread.currentThread().name}")
delay(2000)
println("launch2 ended ${Thread.currentThread().name}")
}
println("go go ${Thread.currentThread().name}")
}
還是先看正確答案吧:
go go main
launch2 started DefaultDispatcher-worker-1
launch1 started main
launch2 ended DefaultDispatcher-worker-1
launch1 ended main
你應(yīng)該已經(jīng)發(fā)現(xiàn)了,這個(gè)是上個(gè)實(shí)例 代碼就有一點(diǎn)點(diǎn)區(qū)別,對(duì),就是因?yàn)檫@個(gè)區(qū)別導(dǎo)致了和前面實(shí)例的輸出順序不一樣,就是它
launch(Dispatchers.Default)
那這玩意是干嘛的呢,為啥它會(huì)導(dǎo)致上面的輸出結(jié)果呢?
首先我們要理解,協(xié)程都有宿主線程,官網(wǎng)管這個(gè)線程叫做 underlying thread, 我們簡(jiǎn)稱它為ut。 所謂的協(xié)程掛起,其實(shí)就是在ut上做個(gè)登記,這個(gè)登記記住了如何恢復(fù)這個(gè)掛起的協(xié)程,也就是所謂的掛起點(diǎn), 此時(shí)另外的等待掛起點(diǎn)協(xié)程就被喚醒。 說(shuō)白了,就是協(xié)程要想執(zhí)行 得等待ut有掛起點(diǎn)或者說(shuō)空閑,當(dāng)然了ut最開始是空閑的
那么這個(gè)代碼launch(Dispatchers.Default)就是指明了使用的ut是一個(gè)共享線程池 最少2,最多=cpu數(shù), 這個(gè)看官網(wǎng)好了。 那么明白了這個(gè)原理后就好分析了,那么我們看出這里面有兩個(gè)宿主線程 utMain 和 utDefault。有3個(gè)協(xié)程 #main, #1, #2
#main 和 #1的宿主線程是 utMain
#2 宿主線程是utDefault
最先得到調(diào)度的是協(xié)程 #main,這顯而易見哈
launch(Dispatchers.Default){
println("launch2 started ${Thread.currentThread().name}")
delay(2000)
println("launch2 ended ${Thread.currentThread().name}")
}
這個(gè)#2 也的確是剛一創(chuàng)建就處于喚醒狀態(tài),因?yàn)閡tDefault并沒被其它協(xié)程“占用”,但凡事有先來(lái)后到 我#main正在執(zhí)行計(jì)算 #2您請(qǐng)稍后, 所以“go go”就先出來(lái)了, #main掛起, #1得以喚醒,但你別忘了 我#2早就喚醒了哦,所以#2先執(zhí)行,輸出了"launch2 started", 說(shuō)到這之后,剩下的都是顯而易見的。
好了,我們循序漸進(jìn)慢慢來(lái),到此為止