庖丁解牛,一文搞懂Kotlin協程的運行原理

挖坑kotlin協程,預計分多篇文章徹底梳理一遍kotlin協程框架,廢話不多說,先從協程作用域開始。

協程作用域CoroutinScope

在了解協程上下文之前,先要談談協程作用域-CoroutinScope,協程作用域可以理解為你創建的協程的約束范圍,協程是運行在你約束的一個范圍內的,這樣就劃分了協程的運行范圍,對于協程的生命周期管理更加規范。每個協程構建器(如啟動、異步等)都是 CoroutineScope 上的擴展,并繼承其 coroutineContext 以自動傳播其所有元素和取消。
CoroutinScope是一個接口,源碼定義如下:

public interface CoroutineScope {
    // 協程上下文,用來管理協程里的上下文元素
    public val coroutineContext: CoroutineContext
}

看看協程框架里提供的全局作用域GlobalScope:

// 注意看它用object修飾了,代表他的生命周期是跟進程綁定的,而且是單例
public object GlobalScope : CoroutineScope {
    /**
     * 一個空的協程上下文
     */
    override val coroutineContext: CoroutineContext
        get() = EmptyCoroutineContext
}

也可以自己根據需求創建作用域,官方推薦使用CoroutineScope(context: CoroutineContext)或者MainScope():

// 創建一個運行在主線程的作用域
public fun MainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatchers.Main)
// 自定義協程上下文的作用域創建方式
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
    ContextScope(if (context[Job] != null) context else context + Job())
協程上下文CoroutineContext

協程上下文從字面意思來看,就是貫穿你創建的某個協程的一個管家,可以結合Android開發中的上下文來理解,它持有協程運行時的各個參數。因為剛開始學習協程,這里先給個模糊描述,否則一開始給出一堆陌生艱澀的術語強行讓你理解,你也會一頭霧水,隨著對協程框架的深入,自然會漸漸領會。
接下來就詳細看看CoroutinContext,它也是一個接口:

public interface CoroutineContext {  
     // 由operator修飾的操作符重載,對應“[]”操作符  
     // 通過key獲取一個Element對象  
     public operator fun <E : Element> get(key: Key<E>): E?  
   
     // 折疊方法,提供一個初始值R和操作lambda,該方法被其子類Element實現
     public fun <R> fold(initial: R, operation: (R, Element) -> R): R  
     // 由operator修飾的操作符重載,對應“+”操作符;
     // 合并兩個CoroutineContext對象中的Element元素,將合并后的上下文返回,如果存在相同key的Element對象,則對其進行覆蓋;
     // EmptyCoroutineContext一個空實現的上下文;
     // CombinedContext是CoroutineContext接口的一個實現類,也是鏈表的具體實現的一個節點,節點存在兩個元素:element 當前的節點的集合元素,left CoroutineContext類型,指向鏈表的下一個元素;
     // 另外plus函數在合并上下文的過程中將Key為ContinuationInterceptor的元素保持在鏈表的尾部,方便其快速的讀取;
     // 先了解ContinuationInterceptor是一個攔截器,下文中會介紹它  

     public operator fun plus(context: CoroutineContext): CoroutineContext =  
         if (context === EmptyCoroutineContext) this else // 如果待合并的context是一個空上下文,返回當前的上下文  
             // fold遍歷context集合  
             context.fold(this) { acc, element ->//acc為當前上下文的集合,element為context集合的元素  
                 val removed = acc.minusKey(element.key)//移除aac集合中的element元素,并返回移除后的一個集合  
                 if (removed === EmptyCoroutineContext)  
                      element // 如果移除后集合是一個空的上下文集合,那么當前element元素為合并后的上下文集合  
                 else {  
                     val interceptor = removed[ContinuationInterceptor]//獲取攔截器  
                     if (interceptor == null) CombinedContext(removed, element) // 如果interceptor為空,生成CombinedContext節點,CombinedContext元素為element,指向的鏈表節點是removed  
                     else {  
                         // 將攔截器移至鏈表尾部方便讀取  
                        val left = removed.minusKey(ContinuationInterceptor)  
                         if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else  
                             CombinedContext(CombinedContext(left, element), interceptor)  
                     }  
                 }  
             }  
   
     // 刪除對應key的Element元素,返回刪除后CoroutineContext  
     public fun minusKey(key: Key<*>): CoroutineContext     
     // 集合中每個元素的key  
     public interface Key<E : Element>  
   
     // 集合中的元素定義,也是一個接口  
     public interface Element : CoroutineContext {  
         // 元素的key  
         public val key: Key<*>  
   
         // 通過key獲取該元素,對應操作符[]  
         public override operator fun <E : Element> get(key: Key<E>): E? =  
             @Suppress("UNCHECKED_CAST")  
             if (this.key == key) this as E else null  
         //// 提供遍歷上下文中所有元素的能力。  
         public override fun <R> fold(initial: R, operation: (R, Element) -> R): R =  
             operation(initial, this)  
   
        // 刪除對應key的Element元素  
         public override fun minusKey(key: Key<*>): CoroutineContext =  
             if (this.key == key) EmptyCoroutineContext else this  
     }  
 }

上面源碼里提到了一個很重要的類CombinedContext,這個類很重要,對于協程上下文的數據結構存儲很重要:

// 左向鏈表實現  
 // element集合元素  
 // left 鏈表的下一個節點  
 internal class CombinedContext(  
     private val left: CoroutineContext,  
     private val element: Element  
 ) : CoroutineContext, Serializable {  
   
     // 在集合中獲取一個以key為鍵的元素  
     override fun <E : Element> get(key: Key<E>): E? {  
         var cur = this  
         while (true) {  
             cur.element[key]?.let { return it }  
             val next = cur.left  
             if (next is CombinedContext) {  
                 cur = next  
             } else {  
                 return next[key]  
             }  
         }  
     }  
   
     // 遍歷集合中所有的元素。  
     public override fun <R> fold(initial: R, operation: (R, Element) -> R): R =  
         operation(left.fold(initial, operation), element)  
   
     // 在集合中刪除一個鍵值為key的元素  
     public override fun minusKey(key: Key<*>): CoroutineContext {  
         element[key]?.let { return left }  
         val newLeft = left.minusKey(key)  
         return when {  
             newLeft === left -> this  
             newLeft === EmptyCoroutineContext -> element  
             else -> CombinedContext(newLeft, element)  
         }  
     }  
   
     // 集合長度  
     private fun size(): Int {  
         var cur = this  
         var size = 2  
         while (true) {  
             cur = cur.left as? CombinedContext ?: return size  
             size++  
         }  
     }  
   
     // 集合中是否包含某個元素  
     private fun contains(element: Element): Boolean =  
         get(element.key) == element  
        ...  
 } 

從以上源碼可以猜得出來,協程上下文是有個集合來管理上下文元素Element的,而這個Element的集合就是協程真正的上下文,里面包含被封裝成Element的各個運行要素。它的結構設計使得很容易把他們拼裝和獲取。舉個例子:

        // 上下文組合添加
        var context = CoroutineName("MainActivity") + Dispatchers.Main
        println("1context:$context")
        // 添加重復類型上下文會覆蓋之前的
        context += Dispatchers.Default
        println("2context:$context")
        // 獲取CoroutineName,注意使用的key
        println("3context:${context[CoroutineName.Key]}")
        // 移除CoroutineName
        context = context.minusKey(CoroutineName.Key)
        println("4context:$context")

輸出結果:

  1context:[CoroutineName(MainActivity), Dispatchers.Main[missing, cause=java.lang.RuntimeException: Stub!]]
  2context:[CoroutineName(MainActivity), Dispatchers.Default]
  3context:CoroutineName(MainActivity)
  4context:Dispatchers.Default

以上的CoroutineName和Dispatchers.main都屬于Element的實現類,也是協程中上下文元素,類似的上下文元素還有很多,比如Job、CoroutineId等等。通過以上的方法可以很好管理這些元素。

協程啟動策略-CoroutineStart

定義協程生成器的啟動選項。定義在一個枚舉類里面:

public enum class CoroutineStart {
    
    DEFAULT,
    LAZY,
    @ExperimentalCoroutinesApi // Since 1.0.0, no ETA on stability
    ATOMIC,
    UNDISPATCHED;
 
    @InternalCoroutinesApi
    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
        }

    @InternalCoroutinesApi
    public operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>): Unit =
        when (this) {
            DEFAULT -> block.startCoroutineCancellable(receiver, completion)
            ATOMIC -> block.startCoroutine(receiver, completion)
            UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion)
            LAZY -> Unit // will start lazily
        }

    /**
     * Returns `true` when [LAZY].
     *
     * @suppress **This an internal API and should not be used from general code.**
     */
    @InternalCoroutinesApi
    public val isLazy: Boolean get() = this === LAZY
}

DEFAULT -- 立即根據其上下文安排協程執行;
LAZY -- 僅在需要時懶惰地啟動協程;
ATOMIC -- 原子(以不可取消的方式)根據其上下文安排執行協程;
UNDISPATCHED -- 立即執行協程,直到當前線程中的第一個掛起點。
這里暫時不展開解釋每個啟動方式的含義,先有個基本印象即可。

launch()方法啟動協程

啟動協程最常用的一個方式,launch()方法是協程框架提供的CoroutineScope的擴展方法,意味著必須在協程作用域里面執行:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext, // 上下文
    start: CoroutineStart = CoroutineStart.DEFAULT, // 啟動策略
    block: suspend CoroutineScope.() -> Unit // 協程代碼塊
): Job {
    // 第一步,先把傳進來的上下文組裝成一個新的
    val newContext = newCoroutineContext(context)
    // 第二步,使用組合后的newContext構建一個Coroutine,分析的時候我們使用DEFAULT策略,所以這里創建的是StandaloneCoroutine,
    // 它實際是個實現了續體Continuation和CoroutineScope和Job的子類,具體后面分析
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    // 第三步,啟動協程
    coroutine.start(start, coroutine, block)
   // 第四步, 作為Job返回這個實例,job可以用來控制協程的一些運行狀態,可以看做是協程體的引用
    return coroutine
}

 // newCoroutineContext是一個擴展函數  
 public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext {  
     // 符號“+”對應CoroutineContext的plus方法  
     val combined = coroutineContext + context  
          // 看下else非debug的情況,得到合并后的combined復制給變量debug  
     val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combined  
     // 實例中調度器使用的Dispatchers.Default,所以這里執行else分支,直接返回coroutineContext + context相加后的結果  
     return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null)  
         debug + Dispatchers.Default else debug  
 }  

現在我們在MainActivity啟動一個協程,一步步看看它是怎么運行的:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        GlobalScope.launch(Dispatchers.Default){
            println("launch test")
        }
    }
}

很簡單的協程,沒有掛起函數,只是在協程里執行了一個println()函數,接下來就跟著launch()方法一步步走下去看看協程是怎么運行起來的。

協程調度器Dispatchers

注意看,launch()方法里我們傳入了Dispatchers.Default,這個對應的是參數context:CoroutinContext,說明它實現了CoroutineContext接口,結合之前分析的launch方法代碼,這個調度器被組合進了newContext傳入到StandaloneCoroutine里去了。來看看Dispatchers.Default是個啥:

/**
 * Groups various implementations of [CoroutineDispatcher].
 */
public actual object Dispatchers {

    @JvmStatic
    public actual val Default: CoroutineDispatcher = DefaultScheduler

    @JvmStatic
    public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher

    @JvmStatic
    public val IO: CoroutineDispatcher = DefaultIoScheduler

    @JvmStatic
    public actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.Unconfined

    @DelicateCoroutinesApi
    public fun shutdown() {
        DefaultExecutor.shutdown()
        // Also shuts down Dispatchers.IO
        DefaultScheduler.shutdown()
    }
}

可以看到Dispatchers.Default是對象聲明Dispatchers的不可變量,類型是CoroutineDispatcher。
注意它是全局單例存在的,代表其他協程使用它的時候,用的都是同一個實例,這里可以提前說明一下Dispatchers.Default維護了一個線程池,所以全局的協程(使用Dispatchers.Default或Dispatchers.IO作為上下文)都是共用一個線程池。這個特性要記住!!
繼續看看Dispatchers.Default的實現:

// Instance of Dispatchers.Default 依然是個單例對象!
internal object DefaultScheduler : SchedulerCoroutineDispatcher(
    CORE_POOL_SIZE, MAX_POOL_SIZE,
    IDLE_WORKER_KEEP_ALIVE_NS, DEFAULT_SCHEDULER_NAME
) {
    // Shuts down the dispatcher, used only by Dispatchers.shutdown()
    internal fun shutdown() {
        super.close()
    }

    // Overridden in case anyone writes (Dispatchers.Default as ExecutorCoroutineDispatcher).close()
    override fun close() {
        throw UnsupportedOperationException("Dispatchers.Default cannot be closed")
    }

    override fun toString(): String = "Dispatchers.Default"
}

沒什么可研究的信息,繼續看他的父類SchedulerCoroutineDispatcher,看到它帶著Scheduler字樣的名字和CORE_POOL_SIZE, MAX_POOL_SIZE這些構造參數,可以判斷它跟線程池有關。

// Instantiated in tests so we can test it in isolation
internal open class SchedulerCoroutineDispatcher(
    private val corePoolSize: Int = CORE_POOL_SIZE,
    private val maxPoolSize: Int = MAX_POOL_SIZE,
    private val idleWorkerKeepAliveNs: Long = IDLE_WORKER_KEEP_ALIVE_NS,
    private val schedulerName: String = "CoroutineScheduler",
) : ExecutorCoroutineDispatcher() {
    // Executor就是java里的線程池頂級接口
    override val executor: Executor
        get() = coroutineScheduler

    // 協程的線程池實例
    private var coroutineScheduler = createScheduler()
    // 協程的線程池類CoroutineScheduler,這里暫時不深究這個類的實現,把它理解成java里的線程池一樣的性質就行
    private fun createScheduler() =
        CoroutineScheduler(corePoolSize, maxPoolSize, idleWorkerKeepAliveNs, schedulerName)
    // 協程的調度方法,最后還是交給了線程池去調度,所謂調度,看來可以理解成線程切換
    override fun dispatch(context: CoroutineContext, block: Runnable): Unit = coroutineScheduler.dispatch(block)

    override fun dispatchYield(context: CoroutineContext, block: Runnable): Unit =
        coroutineScheduler.dispatch(block, tailDispatch = true)

    internal fun dispatchWithContext(block: Runnable, context: TaskContext, tailDispatch: Boolean) {
        coroutineScheduler.dispatch(block, context, tailDispatch)
    }

    override fun close() {
        coroutineScheduler.close()
    }
    ...略
}

從SchedulerCoroutineDispatcher的源碼可以看出,這個類維護了一個線程池,用來執行協程線程的切換。再看看它的父類ExecutorCoroutineDispatcher:

public abstract class ExecutorCoroutineDispatcher: CoroutineDispatcher(), Closeable {
    /** @suppress */
    @ExperimentalStdlibApi
    public companion object Key : AbstractCoroutineContextKey<CoroutineDispatcher, ExecutorCoroutineDispatcher>(
        CoroutineDispatcher,
        { it as? ExecutorCoroutineDispatcher })

    /**
     * Underlying executor of current [CoroutineDispatcher].
     */
    public abstract val executor: Executor

    /**
     * Closes this coroutine dispatcher and shuts down its executor.
     *
     * It may throw an exception if this dispatcher is global and cannot be closed.
     */
    public abstract override fun close()
}

是個抽象類,只是定義了協程調度器的規范,繼續看它的父類CoroutineDispatcher:

public abstract class CoroutineDispatcher :
    AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {

    /** @suppress */
    @ExperimentalStdlibApi
    public companion object Key : AbstractCoroutineContextKey<ContinuationInterceptor, CoroutineDispatcher>(
        ContinuationInterceptor,
        { it as? CoroutineDispatcher })

    public open fun isDispatchNeeded(context: CoroutineContext): Boolean = true
    // 調度方法是在這里定義的
    public abstract fun dispatch(context: CoroutineContext, block: Runnable)

    @InternalCoroutinesApi
    public open fun dispatchYield(context: CoroutineContext, block: Runnable): Unit = dispatch(context, block)

    // 核心方法interceptContinuation,攔截續體,包裝成了成了DispatchedContinuation,DispatchedContinuation也是一個很重要的類
    // 協程的攔截器實現
    public final override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
        DispatchedContinuation(this, continuation)

    ...略
}

// 續體攔截器接口
public interface ContinuationInterceptor : CoroutineContext.Element {
    /**
     * The key that defines *the* context interceptor.
     */
    companion object Key : CoroutineContext.Key<ContinuationInterceptor>

    public fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T>
    ...略
}

通過以上源碼分析,Dispatchers.Default也就是協程調度器CoroutineDispatcher主要有兩個核心方法,
dispatch(context: CoroutineContext, block: Runnable):用來切換線程
interceptContinuation(continuation: Continuation<T>): Continuation<T>:用來攔截續體Continuation,將其包裝成DispatchedContinuation
記住這上面兩個方法,后面的流程分析會多次用到。

續體Continuation

在上面的代碼分析中頻繁出現了一個概念-續體Continuation,這個概念非常重要,協程啟動,掛起,恢復都有它有關,看看它的定義,是一個接口:

public interface Continuation<in T> {
    /**
     * 持有協程上下文
     */
    public val context: CoroutineContext

    /**
     *  核心方法,恢復、開啟協程體的執行入口方法
     *
     */
    public fun resumeWith(result: Result<T>)
}

要理解續體是怎么工作的,我們繼續跟著launch函數走:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext, // 上下文
    start: CoroutineStart = CoroutineStart.DEFAULT, // 啟動策略
    block: suspend CoroutineScope.() -> Unit // 協程代碼塊
): Job {
    // 第一步,先把傳進來的上下文組裝成一個新的
    val newContext = newCoroutineContext(context)
    // 第二步,構建一個Coroutine,分析的時候我們使用DEFAULT策略,所以這里創建的是StandaloneCoroutine,
    // 它實際是個實現了續體Continuation和CoroutineScope和Job的子類,具體后面分析
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    // 第三步,啟動協程
    coroutine.start(start, coroutine, block)
   // 第四步, 作為Job返回這個實例,job可以用來控制協程的一些運行狀態,可以看做是協程體的引用
    return coroutine
}

第三步調用了StandaloneCoroutine的start方法:

public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
        start(block, receiver, this)
    }

接著調用了CoroutineStart的invoke方法(kotlin里invoke方法可以通過對象來調用,這里官方實在很惡心,到處埋雷):

public enum class CoroutineStart {
// 到這里理一下對應關系,入參receiver和completion都是launch方法里StandaloneCoroutine實例coroutine,R泛型這里是協程作用域CoroutineScope
// StandaloneCoroutine也是實現了CoroutineScope接口的,completion則是續體Continuation,StandaloneCoroutine也實現了Continuation
// block是我們業務代碼傳入的協程代碼塊
   public operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>): Unit =
        when (this) {
            // 我們使用的DEFAULT策略,執行這里啟動
            DEFAULT -> block.startCoroutineCancellable(receiver, completion)
            ATOMIC -> block.startCoroutine(receiver, completion)
            UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion)
            LAZY -> Unit // will start lazily
        }
    ... 略
}
// StandaloneCoroutine,其父類實現了Coroutine和CoroutineScope
private open class StandaloneCoroutine(
    parentContext: CoroutineContext,
    active: Boolean
) : AbstractCoroutine<Unit>(parentContext, initParentJob = true, active = active) {
    override fun handleJobException(exception: Throwable): Boolean {
        handleCoroutineException(context, exception)
        return true
    }
}
//  重點看父類AbstractCoroutine,注意它的構造參數parentContext,傳入了父協程上下文
public abstract class AbstractCoroutine<in T>(
    parentContext: CoroutineContext,
    initParentJob: Boolean,
    active: Boolean
) : JobSupport(active), Job, Continuation<T>, CoroutineScope {

    /**
     * 合并了上下文元素
     */
    @Suppress("LeakingThis")
    public final override val context: CoroutineContext = parentContext + this

    /**
     * 關注一下這個方法,續體里定義的抽象方法
     */
    public final override fun resumeWith(result: Result<T>) {
        val state = makeCompletingOnce(result.toState())
        if (state === COMPLETING_WAITING_CHILDREN) return
        afterResume(state)
    }

    protected open fun afterResume(state: Any?): Unit = afterCompletion(state)

    public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
        start(block, receiver, this)
    }
    ... 略
}

繼續跟蹤block.startCoroutineCancellable(receiver, completion),block是我們啟動協程傳入的lambda,startCoroutineCancellable是lambda函數的擴展函數:

public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit = runSafely(completion) {
    createCoroutineUnintercepted(completion).intercepted().resumeCancellableWith(Result.success(Unit))
}

繼續看方法體中第一個方法createCoroutineUnintercepted,這個方法也是suspend () -> T 函數的擴展函數,它是這樣的:

 public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(  
     completion: Continuation<T>  
 ): Continuation<Unit> {  
     // 這里對completion進行了一層封裝 
     val probeCompletion = probeCoroutineCreated(completion)  
    // 判斷函數suspend () -> T 實例是否屬于BaseContinuationImpl的子類
     return if (this is BaseContinuationImpl)  
        // 是的話就調用其create方法
        // 這里涉及到kotlin編譯的問題,用kotlin看源碼往往很蛋疼,這時候就需要把之前的那個協程體反編譯成java來看看
         create(probeCompletion)  
     else  
         createCoroutineFromSuspendFunction(probeCompletion) {  
             (this as Function1<Continuation<T>, Any?>).invoke(it)  
         }  
 }


// MainActivity里協程啟動的方法反編譯成java代碼
BuildersKt.launch$default((CoroutineScope)((CoroutineScope)GlobalScope.INSTANCE)
, (CoroutineContext)((CoroutineContext)Dispatchers.getDefault())
, null
// 這是我們寫的lambda代碼塊,被包裝成了Function2<CoroutineScope, Continuation<? super Unit>, Object>實例,然而
// 其實在接下來還會繼續被包裝成SuspendLambda類對象
, (Function2)((Function2)new Function2<CoroutineScope, Continuation<? super Unit>, Object>(null){
            // 狀態標志位
            int label;
            
            @Nullable
            // 我們寫的lambda表達式被放在了invokeSuspend方法里執行
            public final Object invokeSuspend(@NotNull Object object) {
                IntrinsicsKt.getCOROUTINE_SUSPENDED();
                switch (this.label) {
                    case 0: {
                        ResultKt.throwOnFailure((Object)object);
                        // 我們在協程里就做了一件事執行println
                        System.out.println((Object)"launch test");
                        return Unit.INSTANCE;
                    }
                }
                throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
            }
            // 注意這個函數,就是上面createCoroutineUnintercepted函數里調用到的地方
            @NotNull
            public final Continuation<Unit> create(@Nullable Object value, @NotNull Continuation<?> $completion) {
                return (Continuation)new /* invalid duplicate definition of identical inner class */;
            }

            @Nullable
            public final Object invoke(@NotNull CoroutineScope p1, @Nullable Continuation<? super Unit> p2) {
                return (this.create((Object)p1, p2)).invokeSuspend((Object)Unit.INSTANCE);
            }
        }), (int)2, null);

繼續跟蹤SuspendLambda類及其父類鏈:

// 構造函數的入參completion,也是個續體,注意后面的分析,這個續體是誰
internal abstract class SuspendLambda(
    public override val arity: Int,
    completion: Continuation<Any?>?
) : ContinuationImpl(completion), FunctionBase<Any?>, SuspendFunction {
    constructor(arity: Int) : this(arity, null)

    public override fun toString(): String =
        if (completion == null)
            Reflection.renderLambdaToString(this) // this is lambda
        else
            super.toString() // this is continuation
}

// ContinuationImpl抽象類
internal abstract class ContinuationImpl(
    completion: Continuation<Any?>?,
    private val _context: CoroutineContext?
) : BaseContinuationImpl(completion) {
    // _context協程上下文用的入參completion的上下文
    constructor(completion: Continuation<Any?>?) : this(completion, completion?.context)

    public override val context: CoroutineContext
        get() = _context!!

    @Transient
    private var intercepted: Continuation<Any?>? = null

    // 重點關注這個方法,這個方法先取出了completion上下文中的續體攔截器,然后調用了interceptContinuation方法
    public fun intercepted(): Continuation<Any?> =
        intercepted
            ?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this)
                .also { intercepted = it }

    protected override fun releaseIntercepted() {
        val intercepted = intercepted
        if (intercepted != null && intercepted !== this) {
            context[ContinuationInterceptor]!!.releaseInterceptedContinuation(intercepted)
        }
        this.intercepted = CompletedContinuation // just in case
    }
}

// BaseContinuationImpl抽象類,注意看實現了Continuation接口,說明我們寫的協程方法體也是一個續體Continuation
internal abstract class BaseContinuationImpl(
    // This is `public val` so that it is private on JVM and cannot be modified by untrusted code, yet
    // it has a public getter (since even untrusted code is allowed to inspect its call stack).
    public val completion: Continuation<Any?>?
) : Continuation<Any?>, CoroutineStackFrame, Serializable {
    // This implementation is final. This fact is used to unroll resumeWith recursion.
    // Continuation的核心方法
    public final override fun resumeWith(result: Result<Any?>) {
        // This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume
        var current = this
        var param = result
        while (true) {
            // Invoke "resume" debug probe on every resumed continuation, so that a debugging library infrastructure
            // can precisely track what part of suspended callstack was already resumed
            probeCoroutineResumed(current)
            with(current) {
                val completion = completion!! // fail fast when trying to resume continuation without completion
                val outcome: Result<Any?> =
                    try {
                        // 核心代碼,調用了invokeSuspend函數,前面分析過這個函數里放的就是我們寫的協程方法體block!!!
                        val outcome = invokeSuspend(param)
                        if (outcome === COROUTINE_SUSPENDED) return
                        Result.success(outcome)
                    } catch (exception: Throwable) {
                        Result.failure(exception)
                    }
                releaseIntercepted() // this state machine instance is terminating
                if (completion is BaseContinuationImpl) {
                    // unrolling recursion via loop
                    current = completion
                    param = outcome
                } else {
                    // top-level completion reached -- invoke and return
                    completion.resumeWith(outcome)
                    return
                }
            }
        }
    }
    // 在上面的反編譯的java有對該方法的實現
    protected abstract fun invokeSuspend(result: Result<Any?>): Any?

    protected open fun releaseIntercepted() {
        // does nothing here, overridden in ContinuationImpl
    }

    public open fun create(completion: Continuation<*>): Continuation<Unit> {
        throw UnsupportedOperationException("create(Continuation) has not been overridden")
    }
    // 在上面的反編譯的java有對該方法的實現
    public open fun create(value: Any?, completion: Continuation<*>): Continuation<Unit> {
        throw UnsupportedOperationException("create(Any?;Continuation) has not been overridden")
    }

    public override fun toString(): String =
        "Continuation at ${getStackTraceElement() ?: this::class.java.name}"

    // --- CoroutineStackFrame implementation

    public override val callerFrame: CoroutineStackFrame?
        get() = completion as? CoroutineStackFrame

    public override fun getStackTraceElement(): StackTraceElement? =
        getStackTraceElementImpl()
}

做個小總結:協程啟動函數里的協程體lambda代碼塊實際編譯的時候會被封裝成SuspendLambda對象,而SuspendLambda的繼承鏈路是這樣的:
SuspendLambda->ContinuationImpl->BaseContinuationImpl->Continuation
說明協程體lambda代碼塊也是個續體Continuation,并且在協程啟動方法里會調用自身實現的create(value: Any?, completion: Continuation<>)方法創建實例

繼續回到協程啟動流程:

public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit = runSafely(completion) {
    // 不難發現,協程的啟動就是由續體串起來的,記住每個調用的時候是哪個續體實例,就能記住協程的啟動流程
    createCoroutineUnintercepted(completion) // 第一步,將block轉為SuspendLambda實例,此實例持有了completion,也就持有了創建協程時傳入的上下文,包括攔截器
        .intercepted()  // 第二步,調用了intercepted()方法,這個方法是個Continuation擴展函數
        .resumeCancellableWith(Result.success(Unit)) // 第三步,這個函數依然是Continuation擴展函數
}

// 第二步的擴展函數intercepted()
public actual fun <T> Continuation<T>.intercepted(): Continuation<T> =
    // 調用它的對象正是SuspendLambda,它就是ContinuationImpl的子類,而從上面的ContinuationImpl源碼我們可以
    //看到,ContinuationImpl的intercepted()方法實際是調用了其持有的completion上下文中的續體攔截器,然后調用了interceptContinuation方法。
    // 再往上面看這個completion正是協程啟動launch方法里創建的StandaloneCoroutine,它里面的上下文屬于攔截器性質的就是我們之前研究的Dispatchers.DEFAULT。
    // 由此深挖到最終執行了CoroutineDispatcher類里的interceptContinuation(continuation: Continuation<T>): Continuation<T>方法,它返回了一個
    // 經過包裝后的DispatchedContinuation實例,它也是個續體Continuation,后面會繼續分析
    (this as? ContinuationImpl)?.intercepted() ?: this

// 第三步的擴展函數resumeCancellableWith()
public fun <T> Continuation<T>.resumeCancellableWith(
    result: Result<T>,
    onCancellation: ((cause: Throwable) -> Unit)? = null
): Unit = when (this) {
    // 經過第二步分析我們知道最終我們得到的就是一個DispatchedContinuation對象,所以執行了resumeCancellableWith(result, onCancellation)方法
    is DispatchedContinuation -> resumeCancellableWith(result, onCancellation)
    else -> resumeWith(result)
}

接下來看看DispatchedContinuation類,重點看resumeCancellableWith方法:

// 注意看它的構造方法參數,一個CoroutineDispatcher和Continuation,從CoroutineDispatcher類里interceptContinuation(continuation: Continuation<T>)方法
// 可以看到,構建DispatchedContinuation傳入的dispatcher就是自己(this),而傳入的continuation就是由我們寫的協程lambda表達式封裝成的SuspendLambda。
internal class DispatchedContinuation<in T>(
    @JvmField val dispatcher: CoroutineDispatcher,
    @JvmField val continuation: Continuation<T>
) : DispatchedTask<T>(MODE_UNINITIALIZED), CoroutineStackFrame, Continuation<T> by continuation {
  // delegate是自己,其實就是代理的continuation在干活
    override val delegate: Continuation<T>
            get() = this
      inline fun resumeCancellableWith(
        result: Result<T>,
        noinline onCancellation: ((cause: Throwable) -> Unit)?
    ) {
        val state = result.toState(onCancellation)
        if (dispatcher.isDispatchNeeded(context)) {
            _state = state
            resumeMode = MODE_CANCELLABLE
            // 關鍵步驟,在這里執行了調度方法dispatch,前面我們分析過dispatcher的dispatch方法就是往線程池里調度了一個runnable,真正
          // 執行的地方是run方法,而這個runnable傳的是this,說明DispatchedContinuation是實現了Runnable接口的,而實現的地方其實是在其父類DispatchedTask
            dispatcher.dispatch(context, this)
        } else {
            executeUnconfined(state, MODE_CANCELLABLE) {
                if (!resumeCancelled(state)) {
                    resumeUndispatchedWith(result)
                }
            }
        }
    }
    ...略
}

// 父類DispatchedTask,父類SchedulerTask繼續往上找繼承關系就能找到Runnable接口,這里不深究線程池,會另外開篇講
internal abstract class DispatchedTask<in T>(
    @JvmField public var resumeMode: Int
) : SchedulerTask() {
    internal abstract val delegate: Continuation<T>

    // 關鍵方法run
    public final override fun run() {
        assert { resumeMode != MODE_UNINITIALIZED } // should have been set before dispatching
        val taskContext = this.taskContext
        var fatalException: Throwable? = null
        try {
            val delegate = delegate as DispatchedContinuation<T>

            // 結合前面的代碼,這個continuation是SuspendLambda對象
            val continuation = delegate.continuation
            withContinuationContext(continuation, delegate.countOrElement) {
                val context = continuation.context
                val state = takeState() // NOTE: Must take state in any case, even if cancelled
                val exception = getExceptionalResult(state)
                /*
                 * Check whether continuation was originally resumed with an exception.
                 * If so, it dominates cancellation, otherwise the original exception
                 * will be silently lost.
                 */
                val job = if (exception == null && resumeMode.isCancellableMode) context[Job] else null
                if (job != null && !job.isActive) {
                    // 異常處理
                    val cause = job.getCancellationException()
                    cancelCompletedResult(state, cause)
                    continuation.resumeWithStackTrace(cause)
                } else {
                    if (exception != null) {
                        continuation.resumeWithException(exception)
                    } else {
                        // 正常流程走到這里,調用resume方法,resume也是個擴展函數,真正執行的是continuation的resumeWith方法
                        // 前面分析過SuspendLambda的resumeWith方法是其父類BaseContinuationImpl實現的,里面執行了invokeSuspend()方法,
                        // 至此,我們定義的協程體方法終于得到了執行。
                        continuation.resume(getSuccessfulResult(state))
                    }
                }
            }
        } catch (e: Throwable) {
            // This instead of runCatching to have nicer stacktrace and debug experience
            fatalException = e
        } finally {
            val result = runCatching { taskContext.afterTask() }
            handleFatalException(fatalException, result.exceptionOrNull())
        }
    }
  ...略
 }
    // resume也是個擴展函數
    public inline fun <T> Continuation<T>.resume(value: T): Unit =
        resumeWith(Result.success(value))

至此,在各個續體饒了一大圈終于梳理完了協程是怎么工作的,此篇文章主要是理清楚協程的一些基本概念和運轉流程,還沒涉及到掛起和恢復和協程線程池的管理,下篇將會對協程的掛起和恢復進行剖析。
附:流程圖


dda0721790fe4b419586745f746b77a8.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容