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

Posted 韩曙亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin 协程协程启动 ② ( 多协程控制 | launch 协程执行顺序控制 | Job#join() 函数 | async 协程执行顺序控制 | Deferred#await() 函数 )相关的知识,希望对你有一定的参考价值。

文章目录


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





一、launch 协程执行顺序控制



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

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

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

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() 函数原型如下 : 该函数是挂起函数 , 不会阻塞主线程 ;

/**
 * 挂起协程,直到此作业完成。此调用正常恢复(没有异常)
 * 当作业因任何原因完成且调用协程的[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


完整代码示例 :

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 协程任务 ;

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() 函数原型如下 : 该函数是挂起函数 , 不会阻塞主线程 ;

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


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


完整代码示例 :

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


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 执行完毕")
            
        
    

执行结果 :

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 执行完毕

以上是关于Kotlin 协程协程启动 ② ( 多协程控制 | launch 协程执行顺序控制 | Job#join() 函数 | async 协程执行顺序控制 | Deferred#await() 函数 )的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin 协程协程启动 ⑤ ( 协程作用域构建器 | runBlocking 函数 | coroutineScope 函数 | supervisorScope 函数 )

Kotlin 协程协程启动 ⑤ ( 协程作用域构建器 | runBlocking 函数 | coroutineScope 函数 | supervisorScope 函数 )

Kotlin 协程协程异常处理 ② ( SupervisorJob 协程 | supervisorScope 协程作用域构建器函数 )

Kotlin 协程协程异常处理 ② ( SupervisorJob 协程 | supervisorScope 协程作用域构建器函数 )

Kotlin 协程协程的挂起和恢复 ② ( 协程挂起 和 线程阻塞 对比 )

Kotlin 协程协程的挂起和恢复 ② ( 协程挂起 和 线程阻塞 对比 )