首發(fā)于公眾號(hào): DSGtalk1989
28.協(xié)程基礎(chǔ)
-
準(zhǔn)備工作
如果你使用的是
Android studio
,在build.gradle
文件中柿菩,添加協(xié)程依賴脱衙。
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1'
}
在intelliJ IDEA
中需要進(jìn)入到module setting
的dependency
添加maven
依賴同上
-
最常用的協(xié)程啟動(dòng)
CoroutineScope.launch
分歇,我們可以看一下這個(gè)方法状您,有三個(gè)參數(shù)勒叠。public fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { val newContext = newCoroutineContext(context) val coroutine = if (start.isLazy) LazyStandaloneCoroutine(newContext, block) else StandaloneCoroutine(newContext, active = true) coroutine.start(start, coroutine, block) return coroutine }
三個(gè)參數(shù)分別代表著,協(xié)程的上下文膏孟,啟動(dòng)模式和掛起的函數(shù)眯分。
協(xié)程的上下文和啟動(dòng)模式都有默認(rèn)值,不填寫直接走默認(rèn)柒桑。并且該方法最終會(huì)返回一個(gè)
Job
對(duì)象弊决,我們點(diǎn)進(jìn)去看一下。方法和參數(shù)不多魁淳,我們逐個(gè)的去看飘诗。
-
cancel
取消一個(gè)協(xié)程fun main() { val job = GlobalScope.launch { delay(1000L) println("World!") } job.cancel() println("Hello,") }
只有
Hello,
,沒(méi)有World!
界逛。因?yàn)閰f(xié)程被取消了昆稿。 -
join
等待協(xié)程執(zhí)行完畢fun main() = runBlocking { val job = GlobalScope.launch { delay(1000L) println("World!") delay(1000L) } println("Hello,") job.join() println("Good!") }
和java中的
Thread.join
比較像息拜,都是會(huì)阻塞當(dāng)前線程溉潭,所以最終打印出來(lái)的是Hello, World! Good!
這里需要注意少欺,
join
方法用suspend
修飾喳瓣,是個(gè)掛起函數(shù),掛起函數(shù)必須只能在協(xié)程中進(jìn)行使用赞别,所以外面包裹了一個(gè)runBlocking
畏陕,具體runBlocking
的含義我們之后分析。 -
cancelAndJoin
取消一個(gè)任務(wù)并且等到他徹底結(jié)束public suspend fun Job.cancelAndJoin() { cancel() return join() }
OK仿滔,我們回過(guò)來(lái)繼續(xù)看一下協(xié)程的概念惠毁,本身的協(xié)程是非常的輕量級(jí)的線程。一開始我們就可以把它理解成一個(gè)與當(dāng)前線程區(qū)別開來(lái)的線程堤撵。
-
-
runBlocking
很明顯仁讨,
GlobalScope
的生命周期是全局的,即实昨,完全起了一個(gè)線程洞豁,什么時(shí)候走完完全取決于整個(gè)應(yīng)用程序的生命周期。我們來(lái)看這樣一個(gè)效果fun main() { println("ready") GlobalScope.launch { println("GlobalScope.launch go!") delay(5000L) println("GlobalScope.launch end!") } println("end") }
由于主線程很快的就結(jié)束掉荒给,我們完全沒(méi)有給到協(xié)程啟動(dòng)的機(jī)會(huì)丈挟,jvm迅速的完成了主線程的任務(wù)。導(dǎo)致我們看到的控制臺(tái)輸出是這樣的
ready end
實(shí)際上這里面我們希望的是能夠讓
main
方法把協(xié)程里面的內(nèi)容跑完再結(jié)束的志电,這個(gè)時(shí)候就輪到我們的runBlocking
登場(chǎng)曙咽。Runs new coroutine and blocks current thread interruptibly until its completion.
即起一個(gè)新的協(xié)程,并且立馬阻塞當(dāng)前的線程挑辆,直到協(xié)程完畢例朱。
這里我們需要來(lái)認(rèn)識(shí)一下孝情,協(xié)程中的
sleep
函數(shù)delay
,該函數(shù)只能用在掛起函數(shù)中洒嗤,會(huì)讓協(xié)程暫停一段時(shí)間箫荡。那么這樣一來(lái),我們結(jié)合起來(lái)看
fun main() { println("ready") // 當(dāng)協(xié)程在后臺(tái)等待時(shí), 主線程繼續(xù)執(zhí)行 runBlocking { // 但是這個(gè)表達(dá)式阻塞了主線程 println("runBlocking start") delay(2000L) // ……我們延遲 2 秒來(lái)保證 JVM 的存活 println("runBlocking end") } println("end") }
能夠很清晰的看到渔隶,主線程被阻塞了羔挡,因?yàn)?code>runBlocking的概念,這樣一來(lái)就可以達(dá)到
delay
阻塞了主線程的效果间唉。 -
協(xié)程中疊協(xié)程
協(xié)程中我們可以再起協(xié)程绞灼,舉個(gè)例子,我們瞎看如下代碼呈野。
fun main() { println("ready") // 當(dāng)協(xié)程在后臺(tái)等待時(shí), 主線程繼續(xù)執(zhí)行 runBlocking { // 但是這個(gè)表達(dá)式阻塞了主線程 GlobalScope.launch { // 在后臺(tái)啟動(dòng)新的協(xié)程, 然后繼續(xù)執(zhí)行當(dāng)前程序 println("GlobalScope.launch go!") delay(5000L) // 非阻塞, 等待 1 秒 (默認(rèn)的時(shí)間單位是毫秒) println("GlobalScope.launch end!") } println("runBlocking start") delay(1000L) // ……我們延遲 2 秒來(lái)保證 JVM 的存活 } println("end") }
經(jīng)過(guò)上文的分析低矮,我們知道
runBlocking
會(huì)阻塞當(dāng)前的線程,直到運(yùn)行完它自己的協(xié)程际跪,結(jié)果現(xiàn)在我們?cè)趨f(xié)程中又通過(guò)GlobalScope.launch
起了一個(gè)全局的協(xié)程商佛。考慮到前面講到的生命周期問(wèn)題姆打,我們猜測(cè)runBlocking
不會(huì)去等GlobalScope.launch
良姆,事實(shí)也確實(shí)如此。ready runBlocking start GlobalScope.launch go! end
我們現(xiàn)在去掉
GlobalScope
幔戏,直接走launch
玛追。發(fā)現(xiàn)明顯不同的生命周期,直接launch
的話闲延,這個(gè)協(xié)程的生命周期就是runBlocking
痊剖,也就是說(shuō),哪怕launch
里面消耗的時(shí)間再長(zhǎng)垒玲,main
函數(shù)也需要等到整個(gè)的runBlocking
生命周期走完即launch
里面的協(xié)程也結(jié)束才行陆馁。 -
協(xié)程到底如何輕量
repeat(10_000) { // 啟動(dòng)大量的協(xié)程 runBlocking { launch { print(".") } } }
啟動(dòng)一萬(wàn)個(gè)協(xié)程,輕飄飄的完成了打點(diǎn)的任務(wù)合愈。
Kotlin學(xué)習(xí)筆記之 1 基礎(chǔ)語(yǔ)法
Kotlin學(xué)習(xí)筆記之 2 基本數(shù)據(jù)類型
Kotlin學(xué)習(xí)筆記之 4 循環(huán)控制
Kotlin學(xué)習(xí)筆記之 5 類和對(duì)象
Kotlin學(xué)習(xí)筆記之 8 擴(kuò)展
Kotlin學(xué)習(xí)筆記之 9 數(shù)據(jù)類與密封類
Kotlin學(xué)習(xí)筆記之 12 對(duì)象表達(dá)式和對(duì)象聲明
Kotlin學(xué)習(xí)筆記之 13 基礎(chǔ)操作符run叮贩、with、let佛析、also益老、apply
Kotlin學(xué)習(xí)筆記之 14 包與導(dǎo)入
Kotlin學(xué)習(xí)筆記之 15 伴生對(duì)象
Kotlin學(xué)習(xí)筆記之 18 函數(shù)
Kotlin學(xué)習(xí)筆記之 19 高階函數(shù)與 lambda 表達(dá)式
Kotlin學(xué)習(xí)筆記之 20 內(nèi)聯(lián)函數(shù)
Kotlin學(xué)習(xí)筆記之 21 解構(gòu)聲明
Kotlin學(xué)習(xí)筆記之 28 協(xié)程基礎(chǔ)
Kotlin學(xué)習(xí)筆記之 29 上下文與調(diào)度器
Kotlin學(xué)習(xí)筆記之 30 協(xié)程取消與超時(shí)
Kotlin學(xué)習(xí)筆記之 31 協(xié)程掛起函數(shù)的組合