kotlin: 不要轻易打破协程的父子结构

一,例子一

代码:定义一个线程池

val fixedDispatcher = Executors.newFixedThreadPool(2) {
    Thread(it, "MyFixedThread").apply { isDaemon = false }
}.asCoroutineDispatcher()

调用:

        //处理按钮点击事件
        binding.button1.setOnClickListener {
            runBlocking {
                // 父协程
                val parentJob = launch(fixedDispatcher) {

                    // 1,注意这里
                    launch(Job()) { // 子协程1
                        var i = 0
                        while (isActive) {
                            Thread.sleep(500L)
                            i ++
                            println("First i = $i")
                        }
                    }

                    launch { // 子协程2
                        var i = 0
                        while (isActive) {
                            Thread.sleep(500L)
                            i ++
                            println("Second i = $i")
                        }
                    }
                }

                delay(2000L)

                parentJob.cancel()
                parentJob.join()

                println("End")
            }
        }

运行结果:

image

第二个子协程正常停止,第一个子协程停不下来,
问题原因:
 launch(Job()){} 这个写法使“子协程 1”已经不是 parentJob 的子协程了,
它的父 Job 是我们在 launch 当中传入的 Job() 对象。
所以,当我们调用 parentJob.cancel() 的时候,无法取消“子协程 1”

二,改进:恢复正常的协程父子结构:

代码:

        //处理按钮点击事件
        binding.button2.setOnClickListener {
            runBlocking {
// 父协程
                val parentJob = launch(fixedDispatcher) {

                    // 1,注意这里,取消了参数
                    launch { // 子协程1
                        var i = 0
                        while (isActive) {
                            Thread.sleep(500L)
                            i ++
                            println("First i = $i")
                        }
                    }

                    launch { // 子协程2
                        var i = 0
                        while (isActive) {
                            Thread.sleep(500L)
                            i ++
                            println("Second i = $i")
                        }
                    }
                }

                delay(2000L)

                parentJob.cancel()
                parentJob.join()

                println("End")
            }
        }

运行结果:

image

取消了launch(Job())的参数,使协程的父子结构保持正常,
parentJob 与它内部的子协程 1、子协程 2 之间是父子关系,
因此它们两个都是会响应协程取消的事件的

 

posted @ 2025-08-02 15:06  刘宏缔的架构森林  阅读(3)  评论(0)    收藏  举报