Kotlin学习笔记22 协程part2 join CoroutineScope 协程vs线程

参考链接

示例来自bilibili Kotlin语言深入解析 张龙老师的视频

1 Job的join方法

import kotlinx.coroutines.*
/**
 * Job的join方法
 * 它会挂起协程 直到Job完成
 * join能够实现多个协程合作 即 一个协程等待另一个协程完成后执行
 *
 * Job是一个后台的Job。概念上讲,job是一个可以取消的 有生命周期的东西,job完成后它的生命周期就结束了
 * A background job. Conceptually, a job is a cancellable thing with a life-cycle that culminates in its completion.
 */
fun main() = runBlocking {
    val myJob:Job = GlobalScope.launch {//GlobalScope.launch开启协程 协程不阻塞当前线程 并计时1s
        delay(1000)
        println("Kotlin Coroutines")
    }
    println("hello")// 主线程继续执行 输出hello
    myJob.join() // myJob.join() 挂起协程(GlobalScope.launch创建的协程) 直到myJob执行完毕
    println("world")
}

/**
 * join 方法详解
 * join方法会挂起当前协程直到job完成。当job出于任何原因而完成该调用就可以正常恢复(没有异常的情况下) 并且Job依赖的协程仍然是active的
 * Suspends the coroutine until this job is complete. This invocation resumes normally (without exception)
 * when the job is complete for any reason and the [Job] of the invoking coroutine is still [active][isActive].
 * 如果Job仍然处于new state的状态 该方法也会启动对应的协程
 * This function also [starts][Job.start] the corresponding coroutine if the [Job] was still in _new_ state.
 *
 * 只有这个job的所有子job完成 当前job才能完成
 * Note that the job becomes complete only when all its children are complete.
 *
 * 这个挂起方法是可以取消的并且一直在检查 调用协程Job是否被取消
 * This suspending function is cancellable and **always** checks for a cancellation of the invoking coroutine's Job.
 * 如果在调用此挂起函数时或在挂起时调用协程的 [Job] 被取消或完成,则此函数将抛出 [CancellationException]。
 * If the [Job] of the invoking coroutine is cancelled or completed when this
 * suspending function is invoked or while it is suspended, this function
 * throws [CancellationException].
 *
 * 特别是,这意味着父协程在使用 `launch(coroutineContext) { ... }` 构建器启动的子协程上调用 `join`,如果子进程崩溃,则会抛出 [CancellationException],
 * 除非在上下文中安装了非标准的 [CoroutineExceptionHandler]。
 * In particular, it means that a parent coroutine invoking `join` on a child coroutine that was started using
 * `launch(coroutineContext) { ... }` builder throws [CancellationException] if the child
 * had crashed, unless a non-standard [CoroutineExceptionHandler] is installed in the context.
 *
 * 该函数可以在带有 [onJoin] 子句的 [select] 调用中使用。 使用 [isCompleted] 无需等待即可检查此作业是否已完成。
 * This function can be used in [select] invocation with [onJoin] clause.
 * Use [isCompleted] to check for a completion of this job without waiting.
 *
 * [cancelAndJoin] 函数结合了 [cancel] 和 `join` 的调用。
 * There is [cancelAndJoin] function that combines an invocation of [cancel] and `join`.
 */

/**
 * 输出
 * hello
 * Kotlin Coroutines
 * world
 */

class HelloKotlin5 {
}

2 协程构建器内部隐藏的CoroutineScope实例

import kotlinx.coroutines.*

/**
 * 协程构建器内部隐藏的CoroutineScope实例
 * 外部协程依赖由外部协程创建的内部协程(不是其他协程构建器创建的内部协程)完成
 */

/**
 * 每一个协程构建器(包括runBlocking)都会向其代码块作用域内部添加一个CoroutineScope实例。我们可以在该作用域中启动协程,而无需
 * 显式地将其join到一起,这是因为外部协程(在下面的例子中就是runBlocking创建的协程)会等待该作用域中所有**由外部协程启动的子协程**全部完成后才会完成
 */
fun main() = runBlocking {
    // (每一个协程构建器都会向其代码块作用域内部添加一个CoroutineScope实例)
    // 从runBlocking的外部协程 创建新的子协程 这种情况下 外部协程依赖内部协程执行结束
    /*GlobalScope.*/launch {//注意对比加不加GlobalScope.的情况
        delay(1000)
        println("Kotlin Coroutines")
    }
    println("hello")
}
/**
 * 输出
 * hello
 * Kotlin Coroutines
 */

class HelloKotlin6 {

}

3 通过coroutineScope builder来声明自己的协程作用域

/**
 * 通过coroutineScope builder来声明自己的协程作用域
 */

/**
 * 除去不同的协程构建器(如runBlocking launch)所提供的协程作用域(coroutine scope)外,我们还可以通过coroutineScope builder来声明自己的协程作用域.
 * 该构建器会创建一个协程作用域,并且会等待所有启动的子协程全部完成后自身才会完成。
 *
 * runBlocking与coroutineScope的主要区别是 coroutineScope在等待所有子协程完成Job时不会阻塞当前的线程
 */
fun main() = runBlocking {
    launch {
        delay(1000) // 不阻塞线程 计时1s
        println("my job1")
    }
    println("person")// 第一个输出

    // 通过coroutineScope builder来声明自己的协程作用域
    // 只有所有的子协程完成 它自己才会退出 有点类似join(coroutineScope 也是一个挂起函数)
    coroutineScope {
        launch {// 创建新的子协程 计时3s
            delay(3000)
            println("my job2")
        }
        delay(2000)// 计时2s
        println("hello world") // 第二个输出
    }
    println("welcome")// 最后一个输出
    // 其余按照delay时间 间隔1s依次输出
}

/**
 * 输出
 * person
 * my job1
 * hello world
 * my job2
 * welcome
 */

class HelloKotlin7 {
}

4 runBlocking vs coroutineScope

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

/**
 * runBlocking vs coroutineScope
 * 通过coroutineScope builder来声明自己的协程作用域
 */

/**
 * 除去不同的协程构建器(如runBlocking launch)所提供的协程作用域(coroutine scope)外,我们还可以通过coroutineScope builder来声明自己的协程作用域.
 * 该构建器会创建一个协程作用域,并且会等待所有启动的子协程全部完成后自身才会完成。
 *
 * runBlocking与coroutineScope的主要区别是 coroutineScope在等待所有子协程完成Job时不会阻塞当前的线程。
 *
 * 1.runBlocking并非挂起函数;也就是说,调用它的线程会一直位于该函数中,直到协程执行完毕
 * 2.coroutineScope是挂起函数;也就是说,如果其中的协程挂起。那么coroutineScope函数也会挂起。这样,创建coroutineScope的外层
 * 函数就可以继续在同一个线程中执行了,该线程会“逃离”coroutineScope之外,并且可以做其他事情
 */
fun main() = runBlocking {
    launch {
        delay(1000) // 不阻塞线程 计时1s
        println("my job1")
    }
    println("person")// 第一个输出

    // 通过coroutineScope builder来声明自己的协程作用域
    // 只有所有的子协程完成 它自己才会退出 有点类似join(coroutineScope 也是一个挂起函数)
    coroutineScope {
        launch {// 创建新的子协程 计时3s
            delay(3000)
            println("my job2")
        }
        delay(2000)// 计时2s
        println("hello world") // 第二个输出
    }
    println("welcome")// 最后一个输出
    // 其余按照delay时间 间隔1s依次输出
}

/**
 * 输出
 * person
 * my job1
 * hello world
 * my job2
 * welcome
 *
 * person立即输出
 * my job1 间隔1s后输出
 * hello world 间隔1s后输出
 * my job2 间隔1s后输出
 * welcome和my job2同时输出
 */

class HelloKotlin7_2 {
}

5 协程 vs 线程

// HelloKotlin8.kt
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

/**
 * 协程是轻量级的
 * 对比HelloKotlin8和HelloKotlin9可以看出为什么说协程是轻量级的(相比于线程)
 * 注意这里代码和视频略有不同 增加了计算时间的逻辑 然而这个只是大致统计时间 因为最后一次线程或者协程不一定
 * 是最后一个执行 不过仍然能够看到明显的效果
 *
 * 视频中线程创建超过1万个 JMV就会内存溢出 而协程创建超过一万个却没事
 * 在我的电脑上现象不一样 线程和协程无论创建多少个 都不会内存溢出
 * 但是当数目大于20000时 会发现协程的执行速度远大于线程 不过不同的电脑可能现象不一样
 *
 */

fun main() = runBlocking {
    val start = System.currentTimeMillis()
    val repeatTimes = 20000
    repeat(repeatTimes) {
        // 开启100个协程 协程等待1s后输出A
        launch {
            delay(100)
            println("A")
            if (it == repeatTimes - 1) {
                val totalTime = System.currentTimeMillis() - start
                println("coroutine $repeatTimes cost time $totalTime")
            }
        }
    }
    println("hello world")
}

class HelloKotlin8 {
}


// HelloKotlin9.kt
import java.lang.Thread.sleep

fun main() {
    val start  = System.currentTimeMillis()
    val repeatTimes = 20000
    repeat(repeatTimes) {
        // 开启100个线程 线程等待1s后输出A
        thread {
            sleep(100)
            println("A")
            if (it == repeatTimes -1){
                val totalTime = System.currentTimeMillis() - start
                println("thread $repeatTimes cost time $totalTime")
            }
        }
    }
    println("hello world")
}

class HelloKotlin9 {
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Kotlin协程是一种轻量级的线程处理机制,它可以在不创建新线程的情况下实现异步操作。Kotlin协程的优势在于它提供了一种结构化并发的方式,使得异步代码更加易于编写和维护。下面是深入理解Kotlin协程的一些方法和步骤: 1. 协程的基本概念:协程是一种轻量级的线程处理机制,它可以在不创建新线程的情况下实现异步操作。协程的本质是一种协作式的多任务处理机制,它可以在同一个线程中切换执行不同的任务,从而实现异步操作。 2. 协程的使用方法:在Kotlin中,协程的使用方法非常简单。首先需要导入kotlinx.coroutines库,然后使用launch函数创建一个协程。在协程中可以使用挂起函数来实现异步操作,例如delay函数可以让协程暂停一段时间。 3. 协程的挂起函数:协程的挂起函数是一种特殊的函数,它可以让协程暂停执行,等待某个条件满足后再继续执行。在Kotlin中,常用的挂起函数包括delay函数、withContext函数和async函数等。 4. 协程的上下文:协程的上下文是一种特殊的对象,它包含了协程的执行环境和状态信息。在Kotlin中,协程的上下文可以通过CoroutineContext对象来表示,它包含了协程的调度器、异常处理器和其他一些属性。 5. 协程的异常处理:协程的异常处理是一种特殊的机制,它可以让协程在发生异常时自动恢复或者终止执行。在Kotlin中,协程的异常处理可以通过try-catch语句或者CoroutineExceptionHandler对象来实现。 6. 协程的取消:协程的取消是一种特殊的机制,它可以让协程在不需要继续执行时自动终止。在Kotlin中,协程的取消可以通过cancel函数或者协程作用域来实现。 下面是一个使用Kotlin协程实现异步操作的例子: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { delay(1000L) println("World!") } println("Hello,") job.join() } ``` 输出结果为: ``` Hello, World! ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值