Kotlin协程:生命周期原理,2024年最新android基础面试题及答案pdf

public final override suspend fun join() {

// 调用joinInternal方法

if (!joinInternal()) {

    // 对当前协程的上下文进行检查,检查是否是完成状态

    coroutineContext.checkCompletion()

    // 直接返回,不挂起

    return

}

// 挂起

return joinSuspend()

}

private fun joinInternal(): Boolean {

// 循环

loopOnState { state ->

    // 如果当前是FINAL_*状态,返回false

    if (state !is Incomplete) return false

    // 启动协程,返回结果不为RETRY,则返回true

    if (startInternal(state) >= 0) return true

}

}

// 检查上下文

internal fun CoroutineContext.checkCompletion() {

// 获取上下文的Job对象

val job = get(Job)

// 如果job不为空,同时还未启动,则抛出异常

if (job != null && !job.isActive) throw job.getCancellationException()

}




    join方法中最终通过joinSuspend方法,实现挂起执行,代码如下:



private suspend fun joinSuspend() = suspendCancellableCoroutine { cont ->

cont.disposeOnCancellation(invokeOnCompletion(handler = ResumeOnCompletion(this, cont).asHandler))

}




    joinSuspend方法内部调用了suspendCancellableCoroutine方法。



[]( )1.suspendCancellableCoroutine方法

-------------------------------------------------------------------------------------------------



    这个方法用于挂起当前的协程,同时返回一个可取消的续体。代码如下:



public suspend inline fun suspendCancellableCoroutine(

crossinline block: (CancellableContinuation<T>) -> Unit

): T =

suspendCoroutineUninterceptedOrReturn { uCont ->// 核心方法,返回一个续体

    // 将返回的续体包装成可取消的续体,这里进行了拦截

    val cancellable = CancellableContinuationImpl(uCont.intercepted(), resumeMode = MODE_CANCELLABLE)

    // 将cancellable绑定到uCont.intercepted()返回的续体上,

    // 这样当外部取消内部会得到通知

    cancellable.initCancellability()

    // 执行任务

    block(cancellable)

    // 获取结果

    cancellable.getResult()

}



### []( )1)suspendCoroutineUninterceptedOrReturn方法



    调用该方法会获取当前挂起函数中的续体,并作为参数,去调用block执行。如果需要挂起,则需要在block中返回COROUTINE\_SUSPENDED,并且在合适的时间去手动的调用续体的resumeWith方法,来恢复执行。如果不需要挂起,则不可以对续体进行任何操作。



    该方法暴露的续体未经过拦截器拦截,续体将在被调用的线程上去执行。可以手动调用intercepted方法,对续体进行拦截。



    该方法是协程的内部实现,代码不可见。方法声明如下:



@SinceKotlin(“1.3”)

@InlineOnly

@Suppress(“UNUSED_PARAMETER”, “RedundantSuspendModifier”)

public suspend inline fun suspendCoroutineUninterceptedOrReturn(crossinline block: (Continuation) -> Any?): T {

// 通知虚拟机,block只能调用一次

contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }

throw NotImplementedError("Implementation of suspendCoroutineUninterceptedOrReturn is intrinsic")

}




    **suspendCoroutineUninterceptedOrReturn方法图解:**  

![在这里插入图片描述](https://img-blog.csdnimg.cn/5c48bce7c97b46529dc8d062eca7e123.png#pic_center)



### []( )2)CancellableContinuationImpl类



    CancellableContinuationImpl类与JobSupport类类似,内部也是通过状态机实现的。不同之处在于,它只能有取消监听器,而且最多只能有一个。一旦发生取消,会立即回调取消监听器。它的取消监听器在设置后不能取消。



    CancellableContinuationImpl类中有两个状态机,一个是决策状态机,用于控制挂起和恢复,状态保存在全局变量\_decision中,代码如下:



private const val UNDECIDED = 0 // 初始状态

private const val SUSPENDED = 1 // 挂起状态

private const val RESUMED = 2 // 恢复状态

private val _decision = atomic(UNDECIDED)




    对应的状态转移图如下:  

![在这里插入图片描述](https://img-blog.csdnimg.cn/cbbed2ff30a74ae285b8e7c11d1b1228.png#pic_center)  

    trySuspend与tryResume方法代码如下:



private fun trySuspend(): Boolean {

// 循环

_decision.loop { decision ->

    when (decision) {

        // 进入挂起状态

        UNDECIDED -> if (this._decision.compareAndSet(UNDECIDED, SUSPENDED)) return true

        RESUMED -> return false

        else -> error("Already suspended")

    }

}

}

private fun tryResume(): Boolean {

 // 循环

_decision.loop { decision ->

    when (decision) {

        // 进入恢复状态

        UNDECIDED -> if (this._decision.compareAndSet(UNDECIDED, RESUMED)) return true

        SUSPENDED -> return false

        else -> error("Already resumed")

    }

}

}




    另一个状态机则类似于JobSupport类中的状态机器,状态保存在全局变量\_state中,代码如下:



private val _state = atomic<Any?>(Active)




    状态的划分与对应的外部状态如下:



| 内部状态名 | 内部实现类或对象 | 外部状态 | 备注 |

| --- | --- | --- | --- |

| ACTIVE | Active | Active | 没有监听器 |

| SINGLE\_A | CancelHandler | Active | 有一个取消监听器 |

| CANCELLED | CancelledContinuation | Cancelled | 取消的最终状态 |

| COMPLETED | <Any> | Completed | 完成状态 |



    与JobSupport类相比,CancellableContinuationImpl类的状态类更多的是作为标记来表示一个状态,代码如下:



internal interface NotCompleted

// 实现了NotCompleted接口

private object Active : NotCompleted {

override fun toString(): String = "Active"

}

// 实现了NotCompleted接口

internal abstract class CancelHandler : CancelHandlerBase(), NotCompleted

// 继承自CompletedExceptionally

internal class CancelledContinuation(

continuation: Continuation<*>,

cause: Throwable?,

handled: Boolean

) : CompletedExceptionally(cause ?: CancellationException(“Continuation $continuation was cancelled normally”), handled) {

private val _resumed = atomic(false)

fun makeResumed(): Boolean = _resumed.compareAndSet(false, true)

}




### []( )3)getResult方法



    在suspendCancellableCoroutine方法中,最后调用了CancellableContinuationImpl类的getResult方法,代码如下:



@PublishedApi

internal fun getResult(): Any? {

// 与initCancellability方法相同,监听取消回调

setupCancellation()

// 尝试挂起,成功则返回COROUTINE_SUSPENDED挂起

if (trySuspend()) return COROUTINE_SUSPENDED

// 获取状态

val state = this.state

if (state is CompletedExceptionally) throw recoverStackTrace(state.cause, this)

// 如果当前的模式是取消模式

if (resumeMode.isCancellableMode) {

    // 获取父协程

    val job = context[Job]

    // 如果父协程被取消

    if (job != null && !job.isActive) {

        // 获取异常

        val cause = job.getCancellationException()

        // 通知回调取消监听器,并修改对应状态

        cancelCompletedResult(state, cause)

        // 抛出异常

        throw recoverStackTrace(cause, this)

    }

}

// 获取结果

return getSuccessfulResult(state)

}




    到这里join方法实现了协程的挂起。



    接下来分析,如果在挂起过程中协程发生了取消,将如何恢复续体的执行?



[]( )2.disposeOnCancellation方法

-------------------------------------------------------------------------------------------



private suspend fun joinSuspend() = suspendCancellableCoroutine { cont ->

cont.disposeOnCancellation(invokeOnCompletion(handler = ResumeOnCompletion(this, cont).asHandler))

}




    返回到joinSuspend方法中,在获取到续体cont后,首先将续体和当前的Job对象,封装成了ResumeOnCompletion类的对象,接着调用了asHandler方法,转换成了(cause: Throwable?) -> Unit类型的lambda表达式,然后调用了invokeOnCompletion方法,注册协程执行完成时的回调,同时获取了一个DisposableHandle类型的对象,最后,作为参数传入到disposeOnCancellation方法中,代码如下:



@InternalCoroutinesApi

public fun CancellableContinuation<*>.disposeOnCancellation(handle: DisposableHandle): Unit =

invokeOnCancellation(handler = DisposeOnCancel(handle).asHandler)



    该方法是一个扩展方法。该方法将传入的参数,进一步封装成了DisposeOnCancel对象,最终作为参数,通过调用CancellableContinuation类的invokeOnCancellation方法,注册监听取消。



    假设在挂起到过程中,协程取消会调用DisposeOnCancel的invoke方法,代码如下:



private class DisposeOnCancel(private val handle: DisposableHandle) : CancelHandler() {

override fun invoke(cause: Throwable?) = handle.dispose()

override fun toString(): String = "DisposeOnCancel[$handle]"

}




    DisposeOnCancel类的对象内部会继续调用DisposableHandle对象的dispose方法,这个DisposableHandle是在调用invokeOnCompletion时候返回的,这个对象的实际类型为InvokeOnCompletion,代码如下:



private class InvokeOnCompletion(

job: Job,

private val handler: CompletionHandler

) : JobNode(job) {

override fun invoke(cause: Throwable?) = handler.invoke(cause)

override fun toString() = "InvokeOnCompletion[$classSimpleName@$hexAddress]"

}

public typealias CompletionHandler = (cause: Throwable?) -> Unit




    InvokeOnCompletion类的对象内部又回继续调用CompletionHandler类对象的invoke方法,而这个CompletionHandler对象就是之前传入的ResumeOnCompletion类对象,代码如下:



private class ResumeOnCompletion(

job: Job,

private val continuation: Continuation<Unit>

) : JobNode(job) {

override fun invoke(cause: Throwable?) = continuation.resume(Unit)

override fun toString() = "ResumeOnCompletion[$continuation]"

}




    ResumeOnCompletion类对象的invoke方法,最终调用了续体的reusme方法,恢复了执行。



[]( )四.cancel方法

============================================================================



    cancel方法用于取消一个线程的执行,该方法在JobSupport类中实现,代码如下:



public override fun cancel(cause: CancellationException?) {

cancelInternal(cause ?: defaultCancellationException())

}

@Suppress(“NOTHING_TO_INLINE”)

internal inline fun defaultCancellationException(message: String? = null, cause: Throwable? = null) =

JobCancellationException(message ?: cancellationExceptionMessage(), cause, this)



    cancel方法内部调用了cancelInternal方法,并传入取消异常,代码如下:



public open fun cancelInternal(cause: Throwable) {

cancelImpl(cause)

}




    cancelInternal方法内部调用了cancelImpl方法,代码如下:



// 如果异常已经被处理,则返回true,否则返回false

internal fun cancelImpl(cause: Any?): Boolean {

// 最终状态,默认已经完成

var finalState: Any? = COMPLETING_ALREADY

// 如果协程进入Completing状态

if (onCancelComplete) {

    // 通知子协程进入完成状态

    finalState = cancelMakeCompleting(cause)

    // 如果返回状态为等待子协程完成,则返回true

    if (finalState === COMPLETING_WAITING_CHILDREN) return true

}

// 如果状态为已经完成

if (finalState === COMPLETING_ALREADY) {

    // 则进入Cancelling状态

    finalState = makeCancelling(cause)

}

// 返回

return when {

    finalState === COMPLETING_ALREADY -> true

    finalState === COMPLETING_WAITING_CHILDREN -> true

    finalState === TOO_LATE_TO_CANCEL -> false

    else -> {

        // 其他状态,通过回调通知

        afterCompletion(finalState)

        true

    }

}

}

// 结束的四种状态

// 已经处于完成状态

@SharedImmutable

private val COMPLETING_ALREADY = Symbol(“COMPLETING_ALREADY”)

// 等待子协程进入完成状态

@JvmField

@SharedImmutable

internal val COMPLETING_WAITING_CHILDREN = Symbol(“COMPLETING_WAITING_CHILDREN”)

// 再次重试

@SharedImmutable

private val COMPLETING_RETRY = Symbol(“COMPLETING_RETRY”)

// 由于Finishing类已经密封,因此无法取消

@SharedImmutable

private val TOO_LATE_TO_CANCEL = Symbol(“TOO_LATE_TO_CANCEL”)

// 该变量返回true,表示当前的协程没有block任务待完成,

// 应该马上进入Completing状态,等待子协程完成

internal open val onCancelComplete: Boolean get() = false




    接下来,分析makeCancelling方法如何取消子协程,代码如下:



private fun makeCancelling(cause: Any?): Any? {

// 局部的异常缓存

var causeExceptionCache: Throwable? = null

// 循环

loopOnState { state ->

    when (state) {

        // 如果是Completing状态或者Cancelling状态

        is Finishing -> {

            // 获取最根本的异常

            val notifyRootCause = synchronized(state) {

                // 如果已经密封,则返回TOO_LATE_TO_CANCEL

                if (state.isSealed) return TOO_LATE_TO_CANCEL

                // 是否已经处于Cancelling状态

                val wasCancelling = state.isCancelling

                // 如果传入的异常不为空,或者还未处于Cancelling状态

                if (cause != null || !wasCancelling) {

                    // 则对异常进行包装,并记录到状态中

                    val causeException = causeExceptionCache ?: createCauseException(cause).also { causeExceptionCache = it }

                    state.addExceptionLocked(causeException)

                }

                // 返回根本异常,如果wasCancelling为false,上面addExceptionLocked

                // 会把causeException保存到rootCause

                state.rootCause.takeIf { !wasCancelling }

            }

            // 如果根本异常不为空,说明已经进入Cancelling状态,则通知子协程取消

            notifyRootCause?.let { notifyCancelling(state.list, it) }

            // 返回COMPLETING_ALREADY

            return COMPLETING_ALREADY

        }

        // 如果还没有进入Completing状态或者Cancelling状态

        is Incomplete -> {

            // 获取异常

            val causeException = causeExceptionCache ?: createCauseException(cause).also { causeExceptionCache = it }

            // 如果处于启动的状态

            if (state.isActive) {

                // 调用tryMakeCancelling方法,尝试进入Cancelling状态,

                // 成功则返回COMPLETING_ALREADY

                if (tryMakeCancelling(state, causeException)) return COMPLETING_ALREADY

            } else {// 如果还未启动

                // 则尝试进入Completing状态,

                // 封装成CompletedExceptionally对象

                val finalState = tryMakeCompleting(state, CompletedExceptionally(causeException))

                // 根据返回状态处理

                when {

                    finalState === COMPLETING_ALREADY -> error("Cannot happen in $state")

                    finalState === COMPLETING_RETRY -> return@loopOnState // 继续循环

                    else -> return finalState

                }

            }

        }

        // 其他状态

        else -> return TOO_LATE_TO_CANCEL

    }

}

}




    makeCancelling方法调用notifyCancelling方法取消子协程的执行,代码如下:



private fun notifyCancelling(list: NodeList, cause: Throwable) {

onCancelling(cause)

notifyHandlers<JobCancellingNode<*>>(list, cause)

cancelParent(cause)

}




    notifyCancelling中做了三件事,首先是回调onCancelling方法,代码如下:



protected open fun onCancelling(cause: Throwable?) {}




    当协程完成或者取消时,就会调用一次这个方法。该方法与调用invokeOnCompletion方法并把参数onCancelling设置为true相似。如果cause为空,说明协程是正常执行结束。如果cause为CancellationException类型的对象,说明协程是正常取消,如果是其他的异常,说明是执行过程中发生错误导致。



    接着,在notifyCancelling方法中调用notifyHandlers方法,取消监听器和子协程,代码如下:



private inline fun <reified T: JobNode<*>> notifyHandlers(list: NodeList, cause: Throwable?) {

var exception: Throwable? = null

// 遍历调用invoke方法

list.forEach<T> { node ->

    try {

        node.invoke(cause)

    } catch (ex: Throwable) {

        exception?.apply { addSuppressedThrowable(ex) } ?: run {

            exception =  CompletionHandlerException("Exception in completion handler $node for $this", ex)

        }

    }

}

// 如果取消的过程中发生异常,则调用handleOnCompletionException方法处理

exception?.let { handleOnCompletionException(it) }

}




    如果node是监听器,那它就是(cause: Throwable?) -> Unit类型的lambda表达式,则这时调用invoke方法会直接回调。



    如果node是子协程,那就是一个ChildHandleNode类型的对象,ChildHandleNode对象是在父子协程绑定时返回的对象,后面会提到,它的代码如下:



internal class ChildHandleNode(

parent: JobSupport,

@JvmField val childJob: ChildJob

) : JobCancellingNode(parent), ChildHandle {

override fun invoke(cause: Throwable?) = childJob.parentCancelled(job)

override fun childCancelled(cause: Throwable): Boolean = job.childCancelled(cause)

override fun toString(): String = "ChildHandle[$childJob]"

}




    调用invoke方法,回调用子协程的parentCancelled方法,该方法代码如下:



public final override fun parentCancelled(parentJob: ParentJob) {

cancelImpl(parentJob)

}




    parentCancelled方法也是通过cancelImpl方法实现的。



    最后,在notifyCancelling方法中调用了cancelParent方法取消父协程,代码如下:



// 该方法返回true,表示父协程将处理异常,返回false,则表示不处理

private fun cancelParent(cause: Throwable): Boolean {

// 如果当前的协程是作用域协程,则直接返回true

if (isScopedCoroutine) return true



// 判断当前的异常是否是正常的取消

// 如果子协程是正常的取消,父协程不需要取消自身,除非子协程抛出的是其他的异常

val isCancellation = cause is CancellationException

// 获取父协程的handler

val parent = parentHandle

// 如果当前协程没有父协程,说明他是顶级协程

if (parent === null || parent === NonDisposableHandle) {

    // 直接返回

    return isCancellation

}



// 如果不是顶级协程,则调用childCancelled方法取消自身

return parent.childCancelled(cause) || isCancellation

}

// 作用域协程是在一个封闭作用域内顺序的执行任务,没有任何的并发

// 作用域协程会将遇到的任何错误都抛出

// coroutineScope、withTimeout、runBlocking、ScopeCoroutine都是作用域协程

protected open val isScopedCoroutine: Boolean get() = false




    parent是一个ChildHandle接口指向的对象,该接口最终被上面提到的ChildHandleNode类实现。childCancelled方法最终又会调用JobSupport类的childCancelled方法,代码如下:



// 该方法返回值表示父协程是否取消自身

public open fun childCancelled(cause: Throwable): Boolean {

// 如果是正常取消,则直接返回true

if (cause is CancellationException) return true

// 取消自身

return cancelImpl(cause) && handlesException

}




    childCancelled方法也是通过cancelImpl方法实现的。



    在[Kotlin协程:协程的基础与使用]( )中提到的supervisorScope方法不受子协程取消影响,就是重写了这个方法,代码如下:



public suspend fun supervisorScope(block: suspend CoroutineScope.() -> R): R {

contract {

    callsInPlace(block, InvocationKind.EXACTLY_ONCE)

}

// 获取续体

return suspendCoroutineUninterceptedOrReturn { uCont ->

    // 将续体封装成SupervisorCoroutine协程

    val coroutine = SupervisorCoroutine(uCont.context, uCont)

    // 启动协程执行block

    coroutine.startUndispatchedOrReturn(coroutine, block)

}

}

private class SupervisorCoroutine(

context: CoroutineContext,

uCont: Continuation<T>

) : ScopeCoroutine(context, uCont) {

// 永远返回false

override fun childCancelled(cause: Throwable): Boolean = false

}




[]( )五.delay方法

===========================================================================



    delay方法用于暂停协程的执行,等到指定时间后再恢复协程的执行。delay方法不会挂起线程,同时delay方法导致的挂起是可以被取消中断的。delay方法没有定义在Job接口中,是一个独立的方法,代码如下:



public suspend fun delay(timeMillis: Long) {

// 时间小于0,没有意义,直接返回

if (timeMillis <= 0) return

// 直接挂起,返回可取消的续体

return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> ->

    // 如果时间超过Long.MAX_VALUE,相当于一直等待,可以调用awaitCancellation方法

    if (timeMillis < Long.MAX_VALUE) {

        // 核心实现

        cont.context.delay.scheduleResumeAfterDelay(timeMillis, cont)

    }

}

}




    在上面的代码中,如果时间满足要求,会调用suspendCancellableCoroutine方法挂起,挂起后会获取续体cont的上下文context,并从上下文context中获取一个delay对象,代码如下:



internal val CoroutineContext.delay: Delay get() =

get(ContinuationInterceptor) as? Delay ?: DefaultDelay



    delay对象是一个扩展属性,会从上下文中获取拦截器,并强制转换成Delay接口指向的对象。如果转换失败,则使用默认的DefaultDelay对象。



    接下来会调用Delay接口中定义的scheduleResumeAfterDelay方法,在等待指定时间后,恢复协程的执行。



[]( )1.DefaultDelay

--------------------------------------------------------------------------------



    如果使用的是默认的DefaultDelay对象,则对应的调度器是DefaultExecutor,代码如下:



internal actual val DefaultDelay: Delay = DefaultExecutor




    DefaultExecutor类继承了EventLoopImplBase类,EventLoopImplBase类就是在[Kotlin协程:续体、续体拦截器、调度器]( )中提到的实现了Delay接口的EventLoop。代码如下:



private const val MAX_DELAY_NS = Long.MAX_VALUE / 2

public override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) {

// 转换成纳秒,保证执行精度

val timeNanos = delayToNanos(timeMillis)

// 时间范围判断

if (timeNanos < MAX_DELAY_NS) {

    // 获取当前时间

    val now = nanoTime()

    // 封装成DelayedResumeTask

    DelayedResumeTask(now + timeNanos, continuation).also { task ->

        // 注册续体取消监听

        continuation.disposeOnCancellation(task)

        // 将任务加入到队列中

        schedule(now, task)

    }

}

}




    schedule方法内部最核心的执行会将任务加入到延迟队列中。这个延迟队列的内部是用数组实现的堆,延时任务在添加到队列时会按延迟时间排序。



    每次调用EventLoopImplBase类对象的processNextEvent方法时,会优先判断延迟队列有没有任务,如果有,则继续判断延迟队列第一个任务是否满足时间要求,满足则从延迟队列队首取出,加入到任务队列队尾。之后从任务队列队首取出一个任务执行。



[]( )2.HandlerContext

----------------------------------------------------------------------------------



    如果是在主线程执行协程时调用delay方法,则最后会通过HandlerContext调度器实现延迟,代码如下:



override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) {

// 将恢复续体执行的任务封装成Runnable

val block = Runnable {

    with(continuation) { resumeUndispatched(Unit) }

}

// 延迟执行

handler.postDelayed(block, timeMillis.coerceAtMost(MAX_DELAY))

// 监听取消回调

continuation.invokeOnCancellation { handler.removeCallbacks(block) }

}




    最终通过Handler实现的。



[]( )3.永久等待

------------------------------------------------------------------------



    如果需要实现永远等待,可以使用awaitCancellation方法,该方法代码如下:



public suspend fun awaitCancellation(): Nothing = suspendCancellableCoroutine {}




    该方法直接调用suspendCancellableCoroutine方法挂起协程,只有取消协程时才可以中断。



[]( )六.yield方法

===========================================================================



    yield方法用于挂起当前协程的执行,并让出调度当前协程执行的线程,去执行其他的协程,代码如下:



                               // 获取续体

public suspend fun yield(): Unit = suspendCoroutineUninterceptedOrReturn sc@ { uCont ->

// 获取续体的上下文

val context = uCont.context

// 检查当前协程是否完成

context.checkCompletion()

// 获取拦截后的续体,转换成DispatchedContinuation类型的对象,转换失败则返回

val cont = uCont.intercepted() as? DispatchedContinuation<Unit> ?: return@sc Unit

// 判断是否需要调度

if (cont.dispatcher.isDispatchNeeded(context)) {

    // 如果需要,则直接执行

    cont.dispatchYield(context, Unit)

} else { // 如果不需要调度,可能立即去执行或为Unconfined调度器

    // 创建一个YieldContext上下文,来检测Unconfined调度器

    val yieldContext = YieldContext()

    // 检测Unconfined调度器

    cont.dispatchYield(context + yieldContext, Unit)

    // 如果为Unconfined调度器

    if (yieldContext.dispatcherWasUnconfined) {

        // 调用为Unconfined调度器执行,成功则挂起

        return@sc if (cont.yieldUndispatched()) COROUTINE_SUSPENDED else Unit

    }

    // 如果不是Unconfined调度器,则在dispatchYield方法中已经被调度了

}

// 返回挂起

COROUTINE_SUSPENDED

}




[]( )1.YieldContext类与Unconfined类

---------------------------------------------------------------------------------------------



    YieldContext类是一个上下文对象,用来检测Unconfined调度器是否存在,其内部只有一个变量,代码如下:



internal class YieldContext : AbstractCoroutineContextElement(Key) {

companion object Key : CoroutineContext.Key<YieldContext>



// 默认为false

@JvmField

var dispatcherWasUnconfined = false

}




    在上面的代码中,当调用DispatchedContinuation类的dispatchYield方法,会调用调度器的dispatchYield方法,根据[Kotlin协程:续体、续体拦截器、调度器]( )的分析,dispatchYield方法默认是通过dispatch方法实现的。因此最终会调用Unconfined调度器的dispatch方法。



    Unconfined调度器不会将任务限制到指定的线程上执行。它的dispatch方法根本不会进行调度,所以isDispatchNeeded永远返回false,代码如下:



internal object Unconfined : CoroutineDispatcher() {

// 永远返回false

override fun isDispatchNeeded(context: CoroutineContext): Boolean = false



override fun dispatch(context: CoroutineContext, block: Runnable) {

    // 获取YieldContext

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

总结

笔者之前工作是在金融公司可能并不是特别追求技术,而笔者又是喜欢追求技术的人,所以格格不入,只能把目标放在互联网大厂了。也希望大家都去敢于尝试和追逐自己的梦想!
BATJ大厂Android高频面试题

觉得有收获的记得点赞,关注+收藏哦!你们的点赞就是我的动力!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
atchNeeded(context: CoroutineContext): Boolean = false

override fun dispatch(context: CoroutineContext, block: Runnable) {

    // 获取YieldContext

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-R1sIggJ9-1712798435037)]
[外链图片转存中…(img-dr1BPfmY-1712798435038)]
[外链图片转存中…(img-i1UZUDhX-1712798435039)]
[外链图片转存中…(img-QwsM1Loz-1712798435039)]
[外链图片转存中…(img-LR9bb6Oy-1712798435039)]
[外链图片转存中…(img-ALd2jTuO-1712798435039)]
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-BUHMeUkT-1712798435040)]

总结

笔者之前工作是在金融公司可能并不是特别追求技术,而笔者又是喜欢追求技术的人,所以格格不入,只能把目标放在互联网大厂了。也希望大家都去敢于尝试和追逐自己的梦想!
BATJ大厂Android高频面试题

[外链图片转存中…(img-FDqVUjEJ-1712798435040)]

[外链图片转存中…(img-cFzQksXJ-1712798435040)]

[外链图片转存中…(img-UiMlbCI2-1712798435041)]

[外链图片转存中…(img-ZPbajwO2-1712798435041)]

觉得有收获的记得点赞,关注+收藏哦!你们的点赞就是我的动力!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-Z7qUIMqV-1712798435041)]

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值