• 协程上下文与Job深入解析


    在上一次https://www.cnblogs.com/webor2006/protected/p/12611978.html对于协程的调试与线程之间的切换进行了相关的学习,这次进一步对Job进行进一步的学习,在之前https://www.cnblogs.com/webor2006/p/11730528.html其实已经对Job有了一定的了解,简单回顾一下:

    当时咱们举的一个等待协程代码执行完利用到了Job.join()这个方法的例子, 其实关于Job还有更加深入的东西待挖掘,下面来看一下。

    Job深入解析:

    在上次的咱们使用Job的例子中是通过调用"GlobalScope.launch()"来获得Job对象的:

    因为GlobalScope.launch()本身就是返回的Job对象:

    但是!!对于没有明确返回值Job的场景那又有什么方法能获取到Job本身呢?比如说:

    这个runBlocking的函数的返回值并非是Job的:

    此时先来上一个理论说明:

    协程的Job是归属其上下文(Context)的一部分,Koltin为我们提供了一种简洁的手段来通过协程上下文获取到协程自身的Job对象。我们可以通过coroutineContext[Job]表达式来访问上下文中的Job对象。

    还是有些抽象,下面用例子来进行说明:

    运行看一下:

    此时咱们可以添加上一次https://www.cnblogs.com/webor2006/protected/p/12611978.html学习的协程调试的JVM参数再来看一下协程的信息:

    再运行:

    程序虽简单,但是这里面蕴藏的细节还是相当多的,目前而言存在如下几个疑点:

    1、coroutineContext从哪来的,为啥可以直接使用?

    2、为啥可以直接使用[]来调用,背后我猜肯定是用了运算符重载了,实际是否如猜想呢?

    3、 为啥咱们可以直接使用这个Job,它又是哪里来的?

    4、为啥输出结果是它?

    以上四个问题,下面则来一一进行剖析。

    剖析Job协程上下文的原理:

    接下来则从上面的四个疑问的问题寻找其整个背后的原理。

    疑问一:coroutineContext从哪来的,为啥可以直接使用?

    点击进去查看一下它:

    原来它是在CoroutineScope接口里所定义的一个属性, 而CoroutineScope接口有很多具体的实现类,根据咱们的输出结果来看看到了一个“BlockingCoroutine”,它就是具体的子类之一:

    打开瞅一下这个具体类:

    而这个context的值又是来自于上面这两个属性来构成:

    而runBlocking()里面的代码块就是运行在CoroutineScope中的:

    很明显咱们就可以在这个协程代码块中直接使用coroutineContext了:

    咱们再来读一下该属性的说明:

    从文档说明中也能看到,代码中要访问这个属性唯一的使用就是访问Job,所以正好是咱们目前所使用的代码形式,目前此问题就已经解决了。

    疑问二:为啥可以直接使用[]来调用,背后我猜肯定是用了运算符重载了,实际是否如猜想呢?

    这里还是从源码来找答案:

    此时看一下CoroutineContext这个类:

    而看它里面有一个操作符的重载,如我们所猜想:

     

    所以这也是为啥咱们是用的可空类型来接收:

    关于operator fun的写法在之前https://www.cnblogs.com/webor2006/p/11369333.html的属性委托有过使用,而之所以可以使用[]表达式来访问,这个语法在之前倒还木有学到,这里参考一下这位博主的说明:https://www.jianshu.com/p/e265dbcfe009,其中看一个例子就明白了:

    而我们访问时就可以这样:

    回到咱们这个重载函数的定义:

    很明显咱们也可以用[]来访问这个重载符函数,其中接收的参数是一个Key类型,所以最终我们看到这样的写法了:

    此问题就已经明白了。

    疑问三:为啥咱们可以直接使用这个Job,它又是哪里来的?

    接下来解决最后一个疑点,既然我们在第二个问题分析中可以看出实际是要传一个Key类型的,但是为啥我们传了一个Job呢?

     

    Job和Key之间肯定有联系,下面来剖析一下:

    咱们先来看一下Key的定义:

     

    好,此时再来看一下我们调用时传递的Job的定义:

    很明显,我们直接能传递这个Job的原因就是由于在里面定有伴生对象所达成的,关于伴生对象可以参考https://www.cnblogs.com/webor2006/p/11210181.html,这块的答案就可以揭晓了。

    疑问三:为啥输出的Job是BlockingCoroutine?

    点击瞅一下它的定义:

    而这个BlockingCoroutine的继承体系如下:

     

    所以,最后这个疑点也解决了。

    最后再来修改一下程序:

     

    然后咱们来看一下这个isActive的定义:

    而从它的实现细节就可以看到确实如文档所说:

    咱们来试一下:

    而这个的isActive是定义在Job里面的:

    那,研究这个细节有啥意义呢?结论就是:对于协程是否是isActive其实是取决于它的Job是不是isActive

    以上则对于这个非常简单的例子来完整的阐述了它里面背后的原理,虽说程序简单,但是要搞清楚其背后机制还是不简单的,通过这样的一个彻底分析,对于协程、协程上下文、Job之间的关系也更进一步的。

  • 相关阅读:
    大作文-学以”成人”
    方案类--博物院整改意见
    归纳概括-我国中小学开展研学旅行活动的特点
    短文-网络新一代
    短评
    讲话稿-文明素养教育主题宣传
    检验用户单点登录方案解决
    Spring @Transactional注解
    RPC-局限于java的RMI
    Redis缓存雪崩、击穿、穿透的问题和解决方式
  • 原文地址:https://www.cnblogs.com/webor2006/p/12652844.html
Copyright © 2020-2023  润新知