Kotlin協(xié)程launch啟動(dòng)流程原理詳解
1.launch啟動(dòng)流程
已知協(xié)程的啟動(dòng)方式之一是Globalscope.launch
,那么Globalscope.launch
的流程是怎樣的呢,直接進(jìn)入launch
的源碼開(kāi)始看起。
fun main() { coroutineTest() Thread.sleep(2000L) } val block = suspend { println("Hello") delay(1000L) println("Kotlin") } private fun coroutineTest() { CoroutineScope(Job()).launch { withContext(Dispatchers.IO) { block.invoke() } } }
反編譯后的Java代碼
public final class CoroutineDemoKt { @NotNull private static final Function1 block; public static final void main() { coroutineTest(); Thread.sleep(2000L); } // $FF: synthetic method public static void main(String[] var0) { main(); } @NotNull public static final Function1 getBlock() { return block; } private static final void coroutineTest() { BuildersKt.launch$default(CoroutineScopeKt.CoroutineScope((CoroutineContext)JobKt.Job$default((Job)null, 1, (Object)null)), (CoroutineContext)null, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) { int label; @Nullable public final Object invokeSuspend(@NotNull Object $result) { Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); switch(this.label) { case 0: ResultKt.throwOnFailure($result); CoroutineContext var10000 = (CoroutineContext)Dispatchers.getIO(); Function2 var10001 = (Function2)(new Function2((Continuation)null) { int label; @Nullable public final Object invokeSuspend(@NotNull Object $result) { Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); switch(this.label) { case 0: ResultKt.throwOnFailure($result); Function1 var10000 = CoroutineDemoKt.getBlock(); this.label = 1; if (var10000.invoke(this) == var2) { return var2; } break; case 1: ResultKt.throwOnFailure($result); break; default: throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); } return Unit.INSTANCE; } @NotNull public final Continuation create(@Nullable Object value, @NotNull Continuation completion) { Intrinsics.checkNotNullParameter(completion, "completion"); Function2 var3 = new <anonymous constructor>(completion); return var3; } public final Object invoke(Object var1, Object var2) { return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE); } }); this.label = 1; if (BuildersKt.withContext(var10000, var10001, this) == var2) { return var2; } break; case 1: ResultKt.throwOnFailure($result); break; default: throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); } return Unit.INSTANCE; } @NotNull public final Continuation create(@Nullable Object value, @NotNull Continuation completion) { Intrinsics.checkNotNullParameter(completion, "completion"); Function2 var3 = new <anonymous constructor>(completion); return var3; } public final Object invoke(Object var1, Object var2) { return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE); } }), 3, (Object)null); } static { Function1 var0 = (Function1)(new Function1((Continuation)null) { int label; @Nullable public final Object invokeSuspend(@NotNull Object $result) { Object var3 = IntrinsicsKt.getCOROUTINE_SUSPENDED(); String var2; switch(this.label) { case 0: ResultKt.throwOnFailure($result); var2 = "Hello"; System.out.println(var2); this.label = 1; if (DelayKt.delay(1000L, this) == var3) { return var3; } break; case 1: ResultKt.throwOnFailure($result); break; default: throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); } var2 = "Kotlin"; System.out.println(var2); return Unit.INSTANCE; } @NotNull public final Continuation create(@NotNull Continuation completion) { Intrinsics.checkNotNullParameter(completion, "completion"); Function1 var2 = new <anonymous constructor>(completion); return var2; } public final Object invoke(Object var1) { return ((<undefinedtype>)this.create((Continuation)var1)).invokeSuspend(Unit.INSTANCE); } }); block = var0; } }
先分析一下上面代碼的流程:
- 首先聲明了一個(gè)Function1類(lèi)型的block變量,這個(gè)變量就是demo中的block,然后會(huì)在static函數(shù)中會(huì)被賦值。
- 接下來(lái)就是coroutineTest函數(shù)的調(diào)用。這個(gè)函數(shù)中的第一行代碼就是CoroutineScope的傳參和一些默認(rèn)值
- 然后通過(guò)89行的invoke進(jìn)入到了外層狀態(tài)機(jī)流轉(zhuǎn)的過(guò)程
- 95行的static表示的是內(nèi)部的掛起函數(shù)就是demo中的block.invoke,它是以匿名內(nèi)部類(lèi)的方式實(shí)現(xiàn),然后執(zhí)行內(nèi)部的狀態(tài)機(jī)流轉(zhuǎn)過(guò)程,最后給block賦值。
- block被賦值后最終在
Function1 var10000 = CoroutineDemoKt.getBlock();
被調(diào)用
那么這個(gè)過(guò)程又是如何實(shí)現(xiàn)的,進(jìn)入launch
源碼進(jìn)行查看:
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 }
這里的block
指的就是demo中的block代碼段
再來(lái)看一下里面的幾行代碼的含義:
- newCoroutineContext: 通過(guò)默認(rèn)的或者傳入的context創(chuàng)建一個(gè)新的Context;
- coroutine: launch 會(huì)根據(jù)傳入的啟動(dòng)模式來(lái)創(chuàng)建對(duì)應(yīng)的協(xié)程對(duì)象。這里有兩種,一種是標(biāo)準(zhǔn)的,一種是懶加載的。
- coroutine.start: 嘗試啟動(dòng)協(xié)程
2.協(xié)程是如何被啟動(dòng)的
通過(guò)launch
的源碼可知協(xié)程的啟動(dòng)是通過(guò)coroutine.start
啟動(dòng)的,那么協(xié)程的啟動(dòng)流程又是怎樣的?
public abstract class AbstractCoroutine<in T>( parentContext: CoroutineContext, initParentJob: Boolean, active: Boolean ) : JobSupport(active), Job, Continuation<T>, CoroutineScope { ... /** * 用給定的代碼塊啟動(dòng)這個(gè)協(xié)程并啟動(dòng)策略。這個(gè)函數(shù)在這個(gè)協(xié)程上最多調(diào)用一次。 */ public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) { start(block, receiver, this) } }
start
函數(shù)中傳入了三個(gè)參數(shù),只需要關(guān)注第一個(gè)參數(shù)即可。
public enum class CoroutineStart { ... /** * 用這個(gè)協(xié)程的啟動(dòng)策略啟動(dòng)相應(yīng)的塊作為協(xié)程。 */ public operator fun <T> invoke(block: suspend () -> T, completion: Continuation<T>): Unit = when (this) { DEFAULT -> block.startCoroutineCancellable(completion) ATOMIC -> block.startCoroutine(completion) UNDISPATCHED -> block.startCoroutineUndispatched(completion) LAZY -> Unit // will start lazily } }
啟動(dòng)策略的具體實(shí)現(xiàn)有三種方式,這里只需要分析startCoroutine
,另外兩個(gè)其實(shí)就是它的基礎(chǔ)上增加了一些功能,其中前者代表啟動(dòng)協(xié)程以后可以在等待調(diào)度時(shí)取消,后者表示協(xié)程啟動(dòng)后不會(huì)被分發(fā)。
/** * 創(chuàng)建沒(méi)有接收方且結(jié)果類(lèi)型為T(mén)的協(xié)程,這個(gè)函數(shù)每次調(diào)用時(shí)都會(huì)創(chuàng)建一個(gè)新的可掛起的實(shí)例。 */ public fun <T> (suspend () -> T).startCoroutine( completion: Continuation<T> ) { createCoroutineUnintercepted(completion).intercepted().resume(Unit) }
createCoroutineUnintercepted
在源代碼中只是一個(gè)聲明,它的具體實(shí)現(xiàn)是在IntrinsicsJvm.kt文件中。
//IntrinsicsJvm.kt#createCoroutineUnintercepted /** * 創(chuàng)建沒(méi)有接收方且結(jié)果類(lèi)型為T(mén)的非攔截協(xié)程。這個(gè)函數(shù)每次調(diào)用時(shí)都會(huì)創(chuàng)建一個(gè)新的可掛起的實(shí)例。 */ public actual fun <T> (suspend () -> T).createCoroutineUnintercepted( completion: Continuation<T> ): Continuation<Unit> { val probeCompletion = probeCoroutineCreated(completion) return if (this is BaseContinuationImpl) create(probeCompletion) else createCoroutineFromSuspendFunction(probeCompletion) { (this as Function1<Continuation<T>, Any?>).invoke(it) } }
actual
代表了 createCoroutineUnintercepted()
在 JVM 平臺(tái)的實(shí)現(xiàn)。
createCoroutineUnintercepted
是一個(gè)擴(kuò)展函數(shù),接收者類(lèi)型是一個(gè)無(wú)參數(shù),返回值為 T 的掛起函數(shù)或者 Lambda。
第9行代碼中的this
代表的是(suspend () -> T)
也就是invoke
函數(shù)中的block
變量,這個(gè)block
變量就是demo中的block
代碼段。
第9行的BaseContinuationImpl
是一個(gè)抽象類(lèi)它實(shí)現(xiàn)了Continuation
。
關(guān)于if (this is BaseContinuationImpl)
的結(jié)果暫且不分析,先分析兩種情況下的create函數(shù):
- create(probeCompletion):
//ContinuationImpl.kt#create public open fun create(completion: Continuation<*>): Continuation<Unit> { throw UnsupportedOperationException("create(Continuation) has not been overridden") } public open fun create(value: Any?, completion: Continuation<*>): Continuation<Unit> { throw UnsupportedOperationException("create(Any?;Continuation) has not been overridden") }
這個(gè)create
函數(shù)拋出一個(gè)異常,意思就是這個(gè)create()
沒(méi)有被重寫(xiě),而這個(gè)create()
的重寫(xiě)就是在反編譯后的Java代碼中的create
函數(shù)
@NotNull public final Continuation create(@Nullable Object value, @NotNull Continuation completion) { Intrinsics.checkNotNullParameter(completion, "completion"); Function2 var3 = new <anonymous constructor>(completion); return var3; }
- createCoroutineFromSuspendFunction(probeCompletion):
//IntrinsicsJvm.kt#createCoroutineFromSuspendFunction /** * 當(dāng)一個(gè)被suspend修飾的lambda表達(dá)式?jīng)]有繼承BaseContinuationImpl類(lèi)時(shí),則通過(guò)此方法創(chuàng)建協(xié)程。 * * 它發(fā)生在兩種情況下: * 1.lambda表達(dá)式中調(diào)用了其他的掛起方法 * 2.掛起方法是通過(guò)Java實(shí)現(xiàn)的 * * 必須將它封裝到一個(gè)擴(kuò)展[BaseContinuationImpl]的實(shí)例中,因?yàn)檫@是所有協(xié)程機(jī)制的期望。 */ private inline fun <T> createCoroutineFromSuspendFunction( completion: Continuation<T>, crossinline block: (Continuation<T>) -> Any? ): Continuation<Unit> { val context = completion.context // context為空創(chuàng)建一個(gè)受限協(xié)程 return if (context === EmptyCoroutineContext) //受限協(xié)程:只能調(diào)用協(xié)程作用域中提供的掛起方式掛起,其他掛起方法不能調(diào)用 object : RestrictedContinuationImpl(completion as Continuation<Any?>) { private var label = 0 override fun invokeSuspend(result: Result<Any?>): Any? = when (label) { 0 -> { label = 1 result.getOrThrow() // 如果試圖以異常開(kāi)始,則重新拋出異常(將被BaseContinuationImpl.resumeWith捕獲) block(this) // 運(yùn)行塊,可以返回或掛起 } 1 -> { label = 2 result.getOrThrow() // 這是block掛起的結(jié)果 } else -> error("This coroutine had already completed") } } else //創(chuàng)建一個(gè)正常的協(xié)程 object : ContinuationImpl(completion as Continuation<Any?>, context) { private var label = 0 override fun invokeSuspend(result: Result<Any?>): Any? = when (label) { 0 -> { label = 1 result.getOrThrow() // 如果試圖以異常開(kāi)始,則重新拋出異常(將被BaseContinuationImpl.resumeWith捕獲) block(this) // 運(yùn)行塊,可以返回或掛起 } 1 -> { label = 2 result.getOrThrow() // 這是block掛起的結(jié)果 } else -> error("This coroutine had already completed") } } }
createCoroutineFromSuspendFunction就是當(dāng)一個(gè)被suspend修飾的Lambda表達(dá)式?jīng)]有繼承BaseContinuationImpl是才會(huì)被調(diào)用,然后根據(jù)上下文是否為空創(chuàng)建不同類(lèi)型的協(xié)程。
兩種情況都已經(jīng)分析完了,那么現(xiàn)在if (this is BaseContinuationImpl)
會(huì)執(zhí)行哪一個(gè)呢,首先這里的this
所指的就是demo中的block代碼段,Kotlin編譯器編譯后會(huì)自動(dòng)生成一個(gè)類(lèi)就是上面的static
,它會(huì)繼承SuspendLambda類(lèi),而這個(gè)SuspendLambda類(lèi)繼承自ContinuationImpl,ContinuationImpl繼承自BaseContinuationImpl,因此可以得到判斷結(jié)果為true,
createCoroutineUnintercepted
的過(guò)程就是協(xié)程創(chuàng)建的過(guò)程。
然后就是intercepted函數(shù),這個(gè)函數(shù)的具體實(shí)現(xiàn)也在IntrinsicsJvm.kt中,那么intercepted
又做了什么呢
public expect fun <T> Continuation<T>.intercepted(): Continuation<T> //具體實(shí)現(xiàn) //IntrinsicsJvm.kt#intercepted public actual fun <T> Continuation<T>.intercepted(): Continuation<T> = (this as? ContinuationImpl)?.intercepted() ?: this
首先有個(gè)強(qiáng)轉(zhuǎn),通過(guò)上面的分析這個(gè)強(qiáng)轉(zhuǎn)是一定會(huì)成功的,到這里intercepted
就進(jìn)入到了ContinuationImpl
中了
internal abstract class ContinuationImpl( completion: Continuation<Any?>?, private val _context: CoroutineContext? ) : BaseContinuationImpl(completion) { ... @Transient private var intercepted: Continuation<Any?>? = null //如果沒(méi)有緩存,則從上下文獲取攔截器,調(diào)用interceptContinuation進(jìn)行攔截 //將獲取到的內(nèi)容保存到全局變量 public fun intercepted(): Continuation<Any?> = intercepted ?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this) .also { intercepted = it } }
這里的ContinuationInterceptor
指的就是Demo中傳輸?shù)?code>Dispatcher.IO,默認(rèn)值時(shí)Dispatcher.Default
。
再回到startContinue
中還剩最后一個(gè)resume
:
/** * 恢復(fù)執(zhí)行相應(yīng)的協(xié)程傳遞值作為最后一個(gè)掛起點(diǎn)的返回值。 */ public inline fun <T> Continuation<T>.resume(value: T): Unit = resumeWith(Result.success(value)) public interface Continuation<in T> { /** * 與此延續(xù)相對(duì)應(yīng)的協(xié)程的上下文。 */ public val context: CoroutineContext /** * 恢復(fù)執(zhí)行相應(yīng)的協(xié)程傳遞值作為最后一個(gè)掛起點(diǎn)的返回值。 */ public fun resumeWith(result: Result<T>) }
這里的resume(Unit)
作用就相當(dāng)與啟動(dòng)了一個(gè)協(xié)程。
上面的啟動(dòng)流程中為了方便分析的是CoroutineStart.ATOMIC
,而默認(rèn)的是CoroutineStart.DEFAULT
,下面分析一下DEFAULT
的流程
//Cancellable.kt#startCoroutineCancellable public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit = runSafely(completion) { createCoroutineUnintercepted(completion).intercepted().resumeCancellableWith(Result.success(Unit)) }
startCoroutineCancellable
對(duì)于協(xié)程的創(chuàng)建和攔截與ATOMIC
是一樣的,區(qū)別就在于resumeCancellableWith
//DispatchedContinuation#resumeCancellableWith public fun <T> Continuation<T>.resumeCancellableWith( result: Result<T>, onCancellation: ((cause: Throwable) -> Unit)? = null ): Unit = when (this) { is DispatchedContinuation -> resumeCancellableWith(result, onCancellation) else -> resumeWith(result) } // 我們內(nèi)聯(lián)它來(lái)保存堆棧上的一個(gè)條目,在它顯示的情況下(無(wú)限制調(diào)度程序) // 它只在Continuation<T>.resumeCancellableWith中使用 @Suppress("NOTHING_TO_INLINE") inline fun resumeCancellableWith( result: Result<T>, noinline onCancellation: ((cause: Throwable) -> Unit)? ) { val state = result.toState(onCancellation) //是否需要分發(fā) if (dispatcher.isDispatchNeeded(context)) { _state = state resumeMode = MODE_CANCELLABLE //將可運(yùn)行塊的執(zhí)行分派給給定上下文中的另一個(gè)線(xiàn)程 dispatcher.dispatch(context, this) } else { executeUnconfined(state, MODE_CANCELLABLE) { //協(xié)程未被取消 if (!resumeCancelled(state)) { // 恢復(fù)執(zhí)行 resumeUndispatchedWith(result) } } } } //恢復(fù)執(zhí)行前判斷協(xié)程是否已經(jīng)取消執(zhí)行 inline fun resumeCancelled(state: Any?): Boolean { //獲取當(dāng)前協(xié)程任務(wù) val job = context[Job] //如果不為空且不活躍 if (job != null && !job.isActive) { val cause = job.getCancellationException() cancelCompletedResult(state, cause) //拋出異常 resumeWithException(cause) return true } return false } //我們需要內(nèi)聯(lián)它來(lái)在堆棧中保存一個(gè)條目 inline fun resumeUndispatchedWith(result: Result<T>) { withContinuationContext(continuation, countOrElement) { continuation.resumeWith(result) } }
以上就是Kotlin協(xié)程launch啟動(dòng)流程原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Kotlin協(xié)程launch啟動(dòng)流程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解用RxJava實(shí)現(xiàn)事件總線(xiàn)(Event Bus)
本篇文章主要介紹了用RxJava實(shí)現(xiàn)事件總線(xiàn)(Event Bus),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11Android Zxing二維碼掃描圖片拉伸問(wèn)題的解決方法
這篇文章主要為大家詳細(xì)介紹了Android Zxing二維碼掃描圖片拉伸問(wèn)題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Android側(cè)滑效果簡(jiǎn)單實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android側(cè)滑效果簡(jiǎn)單實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11通過(guò)源碼角度看看AccessibilityService
這篇文章主要給大家介紹了關(guān)于通過(guò)源碼角度看看AccessibilityService的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-06-06Jsoup 抓取頁(yè)面的數(shù)據(jù)實(shí)例詳解
這篇文章主要介紹了Jsoup 抓取頁(yè)面的數(shù)據(jù)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-12-12Android基于OpenCV實(shí)現(xiàn)霍夫直線(xiàn)檢測(cè)
霍夫變換利用點(diǎn)與線(xiàn)之間的對(duì)偶性,將圖像空間中直線(xiàn)上離散的像素點(diǎn)通過(guò)參數(shù)方程映射為霍夫空間中的曲線(xiàn),并將霍夫空間中多條曲線(xiàn)的交點(diǎn)作為直線(xiàn)方程的參數(shù)映射為圖像空間中的直線(xiàn)。給定直線(xiàn)的參數(shù)方程,可以利用霍夫變換來(lái)檢測(cè)圖像中的直線(xiàn)。本文簡(jiǎn)單講解Android的實(shí)現(xiàn)2021-06-06Android開(kāi)發(fā)中Launcher3常見(jiàn)默認(rèn)配置修改方法總結(jié)
這篇文章主要介紹了Android開(kāi)發(fā)中Launcher3常見(jiàn)默認(rèn)配置修改方法,結(jié)合實(shí)例形式分析了Android Launcher3的功能與配置修改相關(guān)操作技巧,需要的朋友可以參考下2017-11-11Android編程ViewPager回彈效果實(shí)例分析
這篇文章主要介紹了Android編程ViewPager回彈效果,以實(shí)例形式較為詳細(xì)的分析了ViewPager回彈效果的相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10android短信管理器SmsManager實(shí)例詳解
這篇文章主要為大家詳細(xì)介紹了android短信管理器SmsManager實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11Android圓形控件實(shí)現(xiàn)畫(huà)圓效果
這篇文章主要為大家詳細(xì)介紹了Android圓形控件實(shí)現(xiàn)畫(huà)圓效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05