美文网首页
协程启动模式

协程启动模式

作者: 竖起大拇指 | 来源:发表于2022-08-18 17:59 被阅读0次

协程启动

我们来看一段最简单的启动协程的方式:

GlobalScope.launch {
    //do what you want
}

那么这段代码会怎么执行呢?我们说过,启动协程需要三样东西,分别是 上下文启动模式协程体,协程体就好比 Thread.run 当中的代码,自不必说。

本文将为大家详细介绍 启动模式。在 Kotlin协程当中,启动模式是一个枚举:

public enum class CoroutineStart {
    DEFAULT,
    LAZY,
    @ExperimentalCoroutinesApi
    ATOMIC,
    @ExperimentalCoroutinesApi
    UNDISPATCHED;
}
  • DEFAULT 立即执行协程体
  • ATOMIC 立即执行协程体,但在开始运行之前无法取消
  • UNDISPATCHED 立即在当前线程执行协程体,直到第一个 suspend 调用
  • LAZY 只有在需要的情况下运行

DEFAULT

四个启动模式当中我们最常用的其实是 DEFAULT 和 LAZY。

DEFAULT是饿汉式启动,launch 调用后,会立即进入待调度状态,一旦调度器 OK 就可以开始执行。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        GlobalScope.launch(start = CoroutineStart.DEFAULT) {
            println(1)
            delay(1000)
            println(3)
        }

        println(2)
    }
}

输出结果:

 2 main
1 DefaultDispatcher-worker-2
3 DefaultDispatcher-worker-2

LAZY

LAZY 是懒汉式启动,launch后并不会有任何调度行为,协程体也自然不会进入执行状态,直到我们需要它执行的时候。这其实就有点儿费解了,什么叫我们需要它执行的时候呢?就是需要它的运行结果的时候,launch调用后会返回一个 Job实例,对于这种情况,我们可以:

  • 调用 Job.start,主动触发协程的调度执行
  • 调用 Job.join,隐式的触发协程的调度执行
    所以这个所谓的”需要“,其实是一个很有趣的措辞,后面你还会看到我们也可以通过 await来表达对Deferred的需要。这个行为与 Thread.join不一样,后者如果没有启动的话,调用join不会有任何作用

ATOMIC

ATOMIC 只有涉及 cancel 的时候才有意义,cancel本身也是一个值得详细讨论的话题,在这里我们就简单认为cancel后协程会被取消掉,也就是不再执行了。那么调用cancel的时机不同,结果也是有差异的,例如协程调度之前、开始调度但尚未执行、已经开始执行、执行完毕等等。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val job = GlobalScope.launch(start = CoroutineStart.ATOMIC) {
          
          println(1)
            delay(1000)
           println(2)
        }
        println(3)
        job.cancel()
        println(4)
      
    }
}

执行结果:

 3 main
4 main
1 DefaultDispatcher-worker-1

我们创建了协程后立即cancel,但由于是 ATOMIC模式,因此协程一定会被调度,因此 1、3、4 一定都会输出。

对应的,如果是DEFAULT 模式,在第一次调度该协程时如果cancel就已经调用,那么协程就会直接被 cancel而不会有任何调用。

需要注意的是,cancel调用一定会将该 job 的状态置为 cancelling,只不过ATOMIC模式的协程在启动时无视了这一状态。

我们使用线程的时候,想要让线程里面的任务停止执行也会面临类似的问题,但遗憾的是线程中看上去与 cancel 相近的 stop 接口已经被废弃,因为存在一些安全的问题。不过随着我们不断地深入探讨,你就会发现协程的 cancel某种意义上更像线程的 interrupt

UNDISPATCHED

有了前面的基础,UNDISPATCHED 就很容易理解了。协程在这种模式下会直接开始在当前线程下执行,直到第一个挂起点,这听起来有点儿像前面的 ATOMIC,不同之处在于 UNDISPATCHED 不经过任何调度器即开始执行协程体。当然遇到挂起点之后的执行就取决于挂起点本身的逻辑以及上下文当中的调度器了。

相关文章

  • 破解 Kotlin 协程(3) - 协程调度篇

    关键词:Kotlin 异步编程 协程 上一篇我们知道了协程启动的几种模式,也通过示例认识了 launch 启动协程...

  • 协程启动模式

    开篇前言 kotlin的协程在初学者看来是一个很神奇的东西,居然能做到用同步的代码块实现异步的调用,其实深入了解你...

  • 协程启动模式

    协程启动 我们来看一段最简单的启动协程的方式: 那么这段代码会怎么执行呢?我们说过,启动协程需要三样东西,分别是 ...

  • kotlin协程

    kotlin协程的启动模式 (枚举类CoroutineStart) CoroutineStart.DEFAULT ...

  • 4.协程的异常处理(2)

    异常的传播异常传播是指异常在父子协程中的传播,什么是父子协程,在当前协程中又启动一个协程,那么这个新启动的协程就是...

  • 协程中launch与withContext都能切换线程,有什么区

    launch、async:启动一个新协程withContext:不启动新协程,在原来的协程中切换线程,需要传入一个...

  • 破解 Kotlin 协程(2) - 协程启动篇

    关键词:Kotlin 协程 启动模式 现在你已经知道协程大概是怎么回事了,也应该想要自己尝试一把了吧。本文将为大家...

  • AndroidのKotlin协程

    参考资料:协程基础 1.协程Coroutines基础 1.1 GlobalScope.launch启动一个独立协程...

  • kotlin<第八篇>:协程的启动与取消

    一、启动构建器 launch与async构建器都用来启动新协程: 等待一个作业: 二、启动模式 三、作用域构建器 ...

  • 3.协程的调度(1)

    上一张通过四种启动模式,我们知道只有调度器ok,才能执行协程里面的代码,那么协程是如何调度的?下面是Corouti...

网友评论

      本文标题:协程启动模式

      本文链接:https://www.haomeiwen.com/subject/sjpugrtx.html