Kotlin中CoroutineScope协程

标题Kotlin协程之CoroutineScope

一、Coroutine的简单理解

线程是操作系统中的CPU调度单位,进程是操作系统中资源划分单位,他们在操作系统中有专门的数据结构代表;而协程在操作系统中没有专门的数据结构代表,所以协程不是由操作系统创建和调度,它是由程序自己创建和调度,由于不需要操作系统调度,所以协程比线程更加的轻量,切换协程比切换线程的开销更小,即它的上下文切换比线程更快,因为切换操作系统线程时一般都会涉及到用户态内核态的转换,这是一个开销相对较大的操作。

协程是依赖于线程实现的,他不能脱离线程而存在,因为线程才是CPU调度的基本单位,协程通过程序的调度可以执行在一个或者多个线程中,所以协程需要运行在线程之中。在Kotlin中,通过Dispatcher实现调度协程。

二、CoroutineContext的元素

构建CoroutineScope使用到的CoroutineContext是一个特殊的集合,这个集合它既有Map的特点,又有Set的特点,即喝的每一个元素都是Element,每个Element都有一个key与之对应,队医相同Key的Element是不可以重复存在的,Element之间是可以通过“+”组合起来。

Coroutine Context主要有以下四部分组成:

· Job:协程的唯一标识,用来控制协程的生命周期(new、active、completing、completed、canceling、cancelled)

· CoroutineDispatcher:指定协程运行的线程(IO、Main、Default、Unconfined)

· CoroutineName:指定协程的名称,默认为coroutine

· CoroutineExceptionHandler:指定协程的异常处理器,用来处理未捕获的异常

三、协程构建器CoroutineBuilder

launch()和async()是CoroutineScope接口的扩展函数,继承了它的coutineContext来自动传播其上下文元素和取消性。挂起函数需要相互传递Continuation,每个挂起函数都要由另一个挂起函数或协程调用,这一切都是从协程构建器创建协程开始的,即作用域函数只能创建子协程,协程构建器能创建根协程或子协程(因为它通过实例调用可以存于普通函数中)。

参数context:指定协程上下文。默认为空的上下文。
参数start:指定协程启动模式。默认为可以立刻被调度的状态。
参数block:协程执行体,即要做的任务。

launch():返回一个Job实例用来管理协程的生命周期。
async():返回一个Deferred实例(Job的子类),通过await()拿到执行的结果(包括异常)。由于await()是挂起函数只能在协程作用域中调用,因此不需要async()做根协程,拿不到值就相当于launch()。通常用于在协程作用域中构建并发子协程合并结果。

四、协程启动模式CoroutineStart

CoroutineStart.DEFAULT —> 协程创建后立即开始调度(不一定此时就被线程执行了),在被线程执行前如果协程被取消,其将直接进入取消响应状态。

CoroutineStart.LAZY —> 只要协程被需要时(包括主动调用start()、join()、await()才会开始调度。如果调度前被取消,协程将进入异常结束状态。

CoroutineStart.ATOMIC —> 协程创建后立刻开始调度,内部代码执行到第一个挂起点之前不响应取消操作(内部第一个挂起函数之前的代码一定执行)。

CoroutineStart.UNDISPATCHED —> 协程被创建后立即在当前函数调用栈中执行(所处的函数在哪个线程就是哪个,即便该协程通过Diapatcher指定了运行的线程),直到内部代码执行到第一个挂起点,挂起函数执行完后,之后的代码就是在Dispatcher指定的线程中运行了。

五、Dispatchers协程调度器

协程是运行在线程之上的。
Dispatchers.Main:只在UI编辑平台才有意义,如安卓,一般Main线程用于UI绘制。在普通JVM工程中无法使用。
Dispatchers.Unconfined:代表无所谓,当前协程可能运行在任意线程之上,不推荐使用。
Dispatchers.Default:CPU密集型任务的线程池。
Dispatchers.IO:IO密集型任务的线程池。

六、创建协程的区别

协程构建器和协程作用域函数中都包含了形参block:suspend CoroutineScope.()->Unit。在这个block中写代码就相当于在协程作用域的一个函数中写代码,因此我们可以通过属性coroutineContext拿到协程上下文,能调用协程构建器去创建子协程,也能调用挂起函数去挂起当前协程。

在这里插入图片描述

七、CoroutineExceptionHandler异常处理

相关源码:

public interface CoroutineExceptionHandler : CoroutineContext.Element {
    public companion object Key : CoroutineContext.Key<CoroutineExceptionHandler>
    public fun handleException(context: CoroutineContext, exception: Throwable)
}

捕获异常:

fun main() = runBlocking {
    val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable -> 		
    	LogUtils("捕获异常:$throwable")
    }
    val scope: CoroutineScope = CoroutineScope(Job())
    val job = scope.launch(exceptionHandler) {
        val s: String? = null
        s!!.length
    }
    job.join()
}

/*
输出信息:
捕获异常:java.lang.NullPointerException
 */
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值