协程是如何实现线程切换的

本文深入探讨协程如何实现线程切换,涉及Continuation、ContinuationInterceptor、CoroutineDispatcher和ThreadContextElement的概念。通过实例解析,阐述了在不同场景下,如runBlocking、suspend函数以及withContext中,协程如何进行线程间切换,确保回调在正确线程执行。
摘要由CSDN通过智能技术生成

本文我们来聊聊协程是如何实现切换线程的。要搞清楚这个问题,我觉得需要搞懂这几个知识点:

  1. Continuation,简单讲可以把它看成是Callback,回调。当协程调用suspend函数,协程会被挂起,当suspend函数执行完成后,会通过Continuation的resumeWith方法,将执行结果返回给协程让协程继续执行。

  2. ContinuationInterceptor顾名思义是Continuation拦截器,也就是Callback拦截器,它的作用就是让回调在指定的线程中执行。假设有这样一个场景,在主线程中开启协程,在子线程中执行耗时操作,当耗时操作执行完毕时,它需要执行回调方法,而回调是需要在主线程中执行的,协程框架内部在协程开启的时候就会通过拦截器将回调与主线程绑定在一起,让回调一定在主线程中执行

  3. CoroutineDispatcher是拦截器的子类,除了拥有拦截器的功能之外,它还有两个重要作用,isDispatchNeeded(context:CoroutineContext)决定回调是否需要分发到其它线程中执行, dispatch(context: CoroutineContext, block: Runnable)将回调分发到指定线程中执行

  4. ThreadContextElement处理协程中的线程的ThreadLocal相关的变量。ThreadLocal很好理解,就是线程私有变量,只能被当前线程访问。那么协程中为什么会有这ThreadLocal呢?举个例子,在同一个线程中执行两个协程,将协程命名为A、B,在执行协程时打印出协程的名称。因为是同一个线程,而且协程的名称是存储在ThreadLocal中的。所以在协程执行的时候,需要将ThreadLocal中保存协程名称的变量修改为当前协程的名称,协程执行完毕时,将变量重置。

首先通过一个例子来讲解Continuation

fun main() = runBlocking(Dispatchers.Main) { // 花括号中是Continuation
    suspendNoChangeThread()
    suspendChangeToIOThread()
    normalFunc()
}

fun normalFunc() {
    // do something
}

suspend fun suspendNoChangeThread() {
    suspendCoroutine<Unit> {
        it.resume(Unit)
    }
}

suspend fun suspendChangeToIOThread(): String {
    return withContext(Dispatchers.IO) {
        Thread.sleep(1000)
        return@withContext &#
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值