前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Kotlin 协程】协程启动 ② ( 多协程控制 | launch 协程执行顺序控制 | Job#join() 函数 | async 协程执行顺序控制 | Deferred#await() 函数 )

【Kotlin 协程】协程启动 ② ( 多协程控制 | launch 协程执行顺序控制 | Job#join() 函数 | async 协程执行顺序控制 | Deferred#await() 函数 )

作者头像
韩曙亮
发布2023-03-30 18:06:44
9550
发布2023-03-30 18:06:44
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

源码地址 : https://download.csdn.net/download/han1202012/87183425

一、launch 协程执行顺序控制


如果需要通过 launch 协程构建器 启动多个协程 , 后面的协程需要等待前面的协程执行完毕 , 在启动靠后的协程 , 实现方案如下 :

调用 Job#join() 函数 , 可以挂起协程 , 等待 launch 中协程体内的任务执行完毕 , 再执行后面的协程任务 ;

代码示例 : 下面的代码中 , 先执行 launchJob 协程 , 调用 launchJob.join() 函数会挂起协程 , 该 launchJob 协程任务执行完毕后 , 才会执行后面的 launch 协程任务 ;

代码语言:javascript
复制
runBlocking {
    // 调用 runBlocking 函数 , 可以将 主线程 包装成 协程
    val launchJob = launch {
        // 调用该挂起函数延迟 100 ms
        delay(100)
        Log.i(TAG, "launchJob 执行完毕")
    }
    // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
    launchJob.join()
    
    val launchJob1 = launch {
        // 调用该挂起函数延迟 100 ms
        delay(100)
        Log.i(TAG, "launchJob1 执行完毕")
    }
}

Job#join() 函数原型如下 : 该函数是挂起函数 , 不会阻塞主线程 ;

代码语言:javascript
复制
/**
 * 挂起协程,直到此作业完成。此调用正常恢复(没有异常)
 * 当作业因任何原因完成且调用协程的[job]仍为[active][isActive]时。
 * 这个函数也[启动][Job。如果[Job]仍然处于_new_状态,则启动]相应的协程。
 *
 * 注意,只有当所有子任务都完成时,作业才算完成。
 *
 * 这个挂起函数是可取消的,并且**总是**检查是否取消了调用协程的Job。
 * 如果调用协程的[Job]被取消或完成
 * 函数被调用,或当它被挂起时,此函数
 * 把[CancellationException]。
 *
 * 特别是,它意味着父协程在子协程上调用' join '时抛出
 * [CancellationException]如果子进程失败,因为子进程的失败会默认取消父进程,
 * 除非子进程是从[supervisor orscope]内部启动的。
 *
 * 此函数可用于带有[onJoin]子句的[select]调用。
 * 使用[isCompleted]检查该作业是否已完成,无需等待。
 *
 * 有一个[cancelAndJoin]函数,它结合了[cancel]和' join '的调用。
 */
public suspend fun join()

源码地址 : https://download.csdn.net/download/han1202012/87183425

完整代码示例 :

代码语言:javascript
复制
package kim.hsl.coroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

class MainActivity : AppCompatActivity(){
    val TAG = "MainActivity"

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

        runBlocking {
            // 调用 runBlocking 函数 , 可以将 主线程 包装成 协程

            val launchJob = launch {
                // 调用该挂起函数延迟 100 ms
                delay(100)
                Log.i(TAG, "launchJob 执行完毕")
            }
            // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
            launchJob.join()

            val launchJob1 = launch {
                // 调用该挂起函数延迟 100 ms
                delay(50)
                Log.i(TAG, "launchJob1 执行完毕")
            }
            // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
            launchJob1.join()

            val launchJob2 = launch {
                // 调用该挂起函数延迟 100 ms
                delay(10)
                Log.i(TAG, "launchJob2 执行完毕")
            }
        }
    }
}
在这里插入图片描述
在这里插入图片描述

二、async 协程执行顺序控制


如果需要通过 async 协程构建器 启动多个协程 , 后面的协程需要等待前面的协程执行完毕 , 在启动靠后的协程 , 实现方案如下 :

调用 Deferred#await() 函数 , 可以挂起协程 , 等待 async 中协程体内的任务执行完毕 , 再执行后面的协程任务 ;

代码示例 : 下面的代码中 , 先执行 asyncDeferred 协程 , 调用 asyncDeferred.await() 函数会挂起协程 , 该 asyncDeferred 协程任务执行完毕后 , 才会执行后面的 async 协程任务 ;

代码语言:javascript
复制
runBlocking {
    // 调用 runBlocking 函数 , 可以将 主线程 包装成 协程
    val asyncDeferred = async {
        // 调用该挂起函数延迟 100 ms
        delay(100)
        Log.i(TAG, "asyncDeferred 执行完毕")
    }
    // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
    asyncDeferred.await()
    val asyncDeferred1 = async {
        // 调用该挂起函数延迟 100 ms
        delay(50)
        Log.i(TAG, "asyncDeferred1 执行完毕")
    }
}

Deferred#await() 函数原型如下 : 该函数是挂起函数 , 不会阻塞主线程 ;

代码语言:javascript
复制
/**
 * 在不阻塞线程的情况下等待该值的完成,并在延迟的计算完成时恢复,
 * 返回结果值,如果取消了延迟,则抛出相应的异常。
 *
 * 这个暂停功能是可以取消的。
 * 如果当前协程的[Job]在此挂起函数等待时被取消或完成,则此函数
 * 立即恢复[CancellationException]。
 * 有**立即取消的保证**。如果在此函数被取消时作业被取消
 * 挂起后,它将无法成功恢复。有关底层细节,请参阅[suspendCancellableCoroutine]文档。
 *
 * 这个函数可以在[select]调用和[onAwait]子句中使用。
 * 使用[isCompleted]检查这个延迟值是否已经完成,无需等待。
 */
public suspend fun await(): T

源码地址 : https://download.csdn.net/download/han1202012/87183425

完整代码示例 :

代码语言:javascript
复制
package kim.hsl.coroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking

class MainActivity : AppCompatActivity(){
    val TAG = "MainActivity"

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

        runBlocking {
            // 调用 runBlocking 函数 , 可以将 主线程 包装成 协程

            val asyncDeferred = async {
                // 调用该挂起函数延迟 100 ms
                delay(100)
                Log.i(TAG, "asyncDeferred 执行完毕")
            }
            // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
            asyncDeferred.await()

            val asyncDeferred1 = async {
                // 调用该挂起函数延迟 100 ms
                delay(50)
                Log.i(TAG, "asyncDeferred1 执行完毕")
            }
            // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
            asyncDeferred1.await()

            val asyncDeferred2 = async {
                // 调用该挂起函数延迟 100 ms
                delay(10)
                Log.i(TAG, "asyncDeferred2 执行完毕")
            }
        }
    }
}

执行结果 :

在这里插入图片描述
在这里插入图片描述

三、完整代码


源码地址 : https://download.csdn.net/download/han1202012/87183425

代码语言:javascript
复制
package kim.hsl.coroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

class MainActivity : AppCompatActivity(){
    val TAG = "MainActivity"

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

        runBlocking {
            // 调用 runBlocking 函数 , 可以将 主线程 包装成 协程

            val launchJob = launch {
                // 调用该挂起函数延迟 100 ms
                delay(100)
                Log.i(TAG, "launchJob 执行完毕")
            }
            // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
            launchJob.join()

            val launchJob1 = launch {
                // 调用该挂起函数延迟 100 ms
                delay(50)
                Log.i(TAG, "launchJob1 执行完毕")
            }
            // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
            launchJob1.join()

            val launchJob2 = launch {
                // 调用该挂起函数延迟 100 ms
                delay(10)
                Log.i(TAG, "launchJob2 执行完毕")
            }
            // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
            launchJob2.join()



            val asyncDeferred = async {
                // 调用该挂起函数延迟 100 ms
                delay(100)
                Log.i(TAG, "asyncDeferred 执行完毕")
            }
            // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
            asyncDeferred.await()

            val asyncDeferred1 = async {
                // 调用该挂起函数延迟 100 ms
                delay(50)
                Log.i(TAG, "asyncDeferred1 执行完毕")
            }
            // 挂起协程 , 等待协程执行完毕会后再执行后面的协程任务
            asyncDeferred1.await()

            val asyncDeferred2 = async {
                // 调用该挂起函数延迟 100 ms
                delay(10)
                Log.i(TAG, "asyncDeferred2 执行完毕")
            }
        }
    }
}

执行结果 :

代码语言:javascript
复制
23:09:21.239  I  launchJob 执行完毕
23:09:21.298  I  launchJob1 执行完毕
23:09:21.331  I  launchJob2 执行完毕
23:09:21.471  I  asyncDeferred 执行完毕
23:09:21.562  I  asyncDeferred1 执行完毕
23:09:21.611  I  asyncDeferred2 执行完毕
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、launch 协程执行顺序控制
  • 二、async 协程执行顺序控制
  • 三、完整代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档