【Kotlin】协程(二)

2.1 协程的阻塞与非阻塞

2.1.1 同步一定阻塞?

同步和阻塞这两个概念在我们学习的时候很容易造成困惑,因为这两个经常放在一起,导致可能存在部分同学认为同步即阻塞,阻塞即同步错误观点。 我们看一下下面的代码:

fun main(){
   val netInfo:NetInfo = getInfoByNetwork()
   val res:Result = processNetInfo(netInfo)
}

上面的代码是我们常见的同步方式,在等待第一步执行完成,拿到 netInfo 后,才能执行第二步,而在这里如果第一步都没有大量的耗时操作,那么这个方法很快就会执行,也就不会阻塞第二步的执行。这里其实就没有阻塞一说,同样的,换成异步方式,在异步的回调中如果存在这耗时操作,那么异步方法内部也是进入阻塞状态,等待完全执行后才会返回。所以 同步异步是处理的方式,阻塞和非阻塞指状态

2.1.2 阻塞与非阻塞

在上一篇我们对协程有了基本的了解,在比较协程和线程的时候,使用了runBlocking函数。当时并没有说明 launchrunBlocking的区别。现在我们详细讲一下这两者的异同,我们以上次的代码作为示例

import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() {
    runBlocking { //阻塞主线程(后续介绍)
        repeat(10000) {
            launch {
                println("Hello")
            }
        }
    }
}

首先这两者都是可以创建一个协程的,区别在于:

  • runBlocking 是创建主协程,为最高级的协程。

  • launch 创建的协程是可以在 runBlocking 中运行的协程,上述的代码可以理解为 在 runBlocking 协程中创建了一个 launch 的子协程。

注意: runBlocking 创建的协程是阻塞当前线程的,会等待所有的子携程全部执行完成。也就是说 **runBlocking **是一个阻塞函数。launch 是一个非阻塞函数

2.2 协程的生命周期

上面的例子里面,我们使用主协程创建子协程的方式实现了一个阻塞和非阻塞的例子,我们接着看下面的例子

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() = runBlocking<Unit> {
    GlobalScope.launch {
       delay(1000L)
        println("world")
    }

    delay(2000L)
    println("hello")
}

在上面的代码中,我们使用 delay方法延迟两秒来保活,确保 GlobalScope.launch{}的执行,如果此处执行的是 IO 操作,这种情况下我们并不知道 IO 操作到底耗时多久,所以通常我们的代码如下

launch{
  ioFun()
}

为了能够让这样场景下,协程能够得到执行,Kotlin 给了一个方法 join,这个方法能够让程序在协程执行完毕之前一直保活,使用方式如下:

import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    val job:Job = launch {
        ioFun()
    }
    println("main fun")
    job.join() //使用 join
}

suspend fun ioFun(){
    delay(2000L)
    println(" io fun")
}

我们这里使用delay方法模拟 IO 操作的延时,然后输出,然后通过 job.join()保证了程序会一直等待协程的结束。这里的等待是非阻塞的,并不会将当前的线程挂起。我们还会注意到在ioFun函数前面有个 suspend修饰,这里修饰表示 ioFun是一个挂起函数,可以被协程内部调用或者其他挂起函数调用,不能在普通方法内部调用。

有等待协程执行结束的方法肯定也存在取消协程的方法,没错,协程的取消可以调用cancel函数来取消协程的执行

我们看下面的示例:

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    val job = launch {
        repeat(1000) { i ->
            println("job: I'm sleeping $i ...")
            delay(500L)
        }
    }
    delay(1300L) // 延迟一段时间
    println("main: I'm tired of waiting!")
    job.cancel() // 取消该作业
    job.join() // 等待作业执行结束
    println("main: Now I can quit.")
}

这里我们每隔 500ms,循环打印 1000 次,同时主协程延迟一段时间,输出的结果如下:

job: I'm sleeping 0 ...
job: I'm sleeping 1 ...
job: I'm sleeping 2 ...
main: I'm tired of waiting!
main: Now I can quit.

我们看到,在循环打印三次之后就停止打印了。协程也就被取消了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0neXiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值