kotlin: 不要破坏结构化并发的结构

一,例子:协程不能被取消:

        //处理按钮点击事件
        binding.button1.setOnClickListener {
            runBlocking {
                val scopeJob = Job()
                val scope = CoroutineScope(scopeJob)

                val coroutineJob = Job()
                scope.launch(coroutineJob) {
                    println("协程启动")
                    delay(200)
                }.invokeOnCompletion { throwable ->
                    if (throwable is CancellationException) {
                        println("协程被取消")
                    }
                }

                // cancel scope while Coroutine performs work
                delay(50)
                println("开始取消协程")
                scope.cancel()
            }
        }

运行结果:

image

原因:通过向协程构建器 launch() 传递我们自己的 job 实例,它成为了新协程的父 job
所以你创建的新协程的父 job 并不是协程作用域的 job,而是新创建的 job 对象。
我们打破了结构化并发,因此当我们取消协程作用域时,协程将不再被取消

二,解决一:只使用scope,不再传入父job

代码:

        //处理按钮点击事件
        binding.button2.setOnClickListener {
            runBlocking {
                val scopeJob = Job()
                val scope = CoroutineScope(scopeJob)

                scope.launch {
                    println("协程启动")
                    delay(200)
                }.invokeOnCompletion { throwable ->
                    if (throwable is CancellationException) {
                        println("协程被取消")
                    }
                }

                // cancel scope while Coroutine performs work
                delay(50)
                println("开始取消协程")
                scope.cancel()
            }
        }

运行结果:

image

三,解决二:取消时使用传入的父job: coroutineJob,不再使用scope

代码:

       //处理按钮点击事件
        binding.button4.setOnClickListener {
            runBlocking {
                val coroutineJob = Job()
                launch(coroutineJob) {
                    println("协程启动")
                    delay(200)
                }.invokeOnCompletion { throwable ->
                    if (throwable is CancellationException) {
                        println("协程被取消")
                    }
                }

                // cancel scope while Coroutine performs work
                delay(50)
                println("开始取消协程")
                coroutineJob.cancel()
            }
        }

运行结果:

image

posted @ 2025-08-09 13:41  刘宏缔的架构森林  阅读(26)  评论(0)    收藏  举报