Kotlin 协程相关基础

这段话来自kolin中文网:本质上,协程是轻量级的线程。 它们在某些 CoroutineScope 上下文中与 launch 协程构建器 一起启动。

1.GlobalScope启动全局新协程

  这里我们在 GlobalScope 中启动了一个新的协程,这意味着新协程的生命周期只受整个应用程序的生命周期限制。

    fun main1() {
        GlobalScope.launch {
            // 在后台启动一个新的协程并继续
            delay(1000L) // 非阻塞的等待 1 秒钟(默认时间单位是毫秒)
            Log.i("协程---", "G.launch.delay(1000L) " + System.currentTimeMillis())//-----1
        }
        Log.i("协程---Start,", "协程" + System.currentTimeMillis())//主线程的代码会立即执行-----0秒开始执行
        Thread.sleep(2000L) // 阻塞主线程 2 秒钟来保证 JVM 存活
        Log.i("协程---", "Thread.sleep(2000L)" + System.currentTimeMillis())//-----2
        runBlocking {
            // 但是这个表达式阻塞了主线程
            delay(2000L)  // ……我们延迟 2 秒来保证 JVM 的存活
            Log.i("协程---", "runBlocking(2000L) " + System.currentTimeMillis())//-----4
        }
    }

  注意这里 Thread.sleep 线程相关,会阻塞主线程。一下runBlocking中多延迟了两秒,而delay没有阻塞主线程

输出结果:

 

2.强制阻塞(runBlocking)

第一个示例在同一段代码中混用了 非阻塞的 delay(……)阻塞的 Thread.sleep(……)。 这容易让我们记混哪个是阻塞的、哪个是非阻塞的。 让我们显式使用 runBlocking 协程构建器来阻塞:

// 桥接阻塞与非阻塞,里面的delay都是看起来是顺序执行,阻塞了彼此
    fun main2() = runBlocking {
        GlobalScope.launch {
            // 在后台启动一个新的协程并继续
            delay(1000L)
            Log.i("协程---", "G.launch.delay(1000L) " + System.currentTimeMillis())//-----
        }
        Log.i("协程---Start", "协程" + System.currentTimeMillis()) // 主协程在这里会立即执行
        delay(2000L)      // 延迟 2 秒来保证 JVM 存活
        Log.i("协程---", "delay(2000)" + System.currentTimeMillis())//-----
        delay(2000L)      // 延迟 2 秒来保证 JVM 存活
        Log.i("协程---", "delay(2000)" + System.currentTimeMillis())//-----
    }

输出:

3.join 等待作业

控制异步程序执行的简单明了的一种方式:作业执行完毕后 才走 job。join之后的代码

 fun main3() = runBlocking {
        val job = GlobalScope.launch {
            // 启动一个新协程并保持对这个作业的引用
            delay(1000L)
            Log.i("协程---", "G.launch.delay(1000L) " + System.currentTimeMillis())//-----1
        }
        Log.i("协程---", "start " + System.currentTimeMillis())//-----0
        job.join() // 等待直到子协程执行结束
        Log.i("协程---", "job.join(2000L)join后" + System.currentTimeMillis())//-----1
    }

输出:

   

 

4 结构化并发,记住与3相互比较一下 更简洁 更常用

这里注意,lauch中耗时操作 执行后 runBlocking 才会结束 而global.lauch不属于当前block作用域
也就是说,外面调用什么东西的话 完全可以等到当前耗时操作获取到结果后获取,这样就不用写join了
runBlocking所包裹到代码中,才可以直接有lauch{},但是这时候也就限制了只有lauch挂起执行完毕,此blocking块才能结束,才能继续走block以外的代码
fun main4() = runBlocking {
        val job = launch {
            // 启动一个新协程并保持对这个作业的引用
            delay(1000L)
            Log.i("协程---","G.launch.delay(1000L) "+System.currentTimeMillis())//-----2
//            main4lauch()
        }
        Log.i("协程---", "Start " + System.currentTimeMillis())//-----2
    }
this.main4()
Log.i("协程---这一行主线程,最后执行", "协程" + System.currentTimeMillis())//-----1

输出:

5 重要:协程作用域构建器:coroutineScope

//作用域构建器
/* 协程作用域 执行完毕后外面线程才会执行
*   不加协程作用域,外面runblock会先执行
*   如果有内嵌coroutineScope,则runblock中初层代码在内嵌scope之后执行,否则直接最先就执行了
*
*   1。有coroutineScope,: 先(lauch或coroutinescope.lauch, -> 初层代码)
*
*   2。无coroutineScope : 先 初层代码 -》 lauch(或同时)
*
* */
fun main5() = runBlocking {
        // this: CoroutineScope
        launch {
            Log.i("协程---( lauch", "执行lunch" + System.currentTimeMillis())// 这一行会在内嵌 launch 之前输------0
            delay(20000L)
            Log.i("协程---( lauch", "执行完了lunch" + System.currentTimeMillis())// 这一行会在内嵌 launch 之前输------2
        }
        coroutineScope{
            // 创建一个协程作用域
            launch {
                Log.i("协程---( coroutinelauch", "执行coroutinelauch" + System.currentTimeMillis())// 这一行会在内嵌 launch 之前输------0
                delay(5000L)
                Log.i("协程---( Coroutine lauch", "coroutinelauch" + System.currentTimeMillis())//----5
            }
            delay(1000L)
            Log.i("协程---( coroutineScope", "launch前" + System.currentTimeMillis())// 这一行会在内嵌 launch 之前输出-----1
        }
        Log.i("协程---( Tasklaunch", "launch后" + System.currentTimeMillis()) // 这一行在 内嵌 launch 执行完毕后才输出----5

    }

输出:

6.守护线程的一种方式

重复五次 repeat(5)

    fun main6() = runBlocking {
        //sampleStart
        GlobalScope.launch {
            repeat(5) { i ->
                delay(500L)
                Log.i("协程---( im slepping $i", "500l后" + System.currentTimeMillis()) //
            }
        }
        Log.i("协程---( im slepping", "延迟1300前" + System.currentTimeMillis()) //
        delay(1300L) // just quit after delay
        Log.i("协程---( im slepping", "延迟1300l" + System.currentTimeMillis()) //
        //sampleEnd
    }

输出:

 

7 suspend 关键字

运行在lauch中的挂起函数要添加suspend关键字如:

fun main4() = runBlocking {
        val job = launch {
            // 启动一个新协程并保持对这个作业的引用
            main4lauch()
        }
        Log.i("协程---", "Start " + System.currentTimeMillis())//----
    }

    suspend fun main4lauch() {
        delay(1000L)
        Log.i("协程---mai4(1000L", "函数重构" + System.currentTimeMillis())//----
    }

lauch本身就是suspend的

输出:

 

 

 

你可能感兴趣的:(Kotlin 协程相关基础)