news 2026/4/18 19:36:48

Android开发:Kotlin协程并发模型(人话版)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android开发:Kotlin协程并发模型(人话版)

一、核心基础:协程的并发与并行

1. 核心前提:并发 ≠ 并行

  • 并发:单核CPU场景下,任务快速切换(毫秒/微秒级),看起来像同时执行,本质是「轮流执行」(如单线程内的协程、单线程多任务)。

  • 并行:多核CPU场景下,多个任务在不同核心上物理同时执行,本质是「真正同时跑」。

2. 协程的并发与并行逻辑

  • 单线程内的协程:仅能实现「并发」,依赖协程主动让出CPU(如await、IO等待),切换速度比线程快100~1000倍(无内核切换开销)。

  • 协程的「并行」:无法单独实现,必须依托「多线程/多进程 + 多核CPU」—— 协程挂靠在操作系统线程上,多个线程分配到不同CPU核心,实现协程并行。

  • 关键结论:同一时刻,真正在CPU上运行的协程数量 ≤ 活跃的操作系统线程数量(协程必须挂靠线程执行,一个线程同一时刻只能执行一个协程)。

二、协程运行机制(结合实战代码)

1. 实战代码解析(IO并行请求)

suspendfunloadData():CombinedData=coroutineScope{valuserDeferred=async(Dispatchers.IO){api.getUser()}valnewsDeferred=async(Dispatchers.IO){api.getNews()}CombinedData(userDeferred.await(),newsDeferred.await())}

2. 逐步运行逻辑

  • 进入coroutineScope:创建父协程,父协程运行在调用它的线程(如安卓主线程)。

  • 启动async协程:两个async分别创建子协程,指定Dispatchers.IO,提交到IO线程池,线程池分配空闲线程(如Thread-IO1、Thread-IO2)执行网络请求;async不等待,直接返回Deferred对象,代码继续执行。

  • 执行await():父协程调用await()的瞬间,会「挂起」并「立刻释放当前占用的线程」(无需等待所有await或所有子协程完成)。

  • 协程恢复:子协程执行完成(网络请求结束),父协程重新获取线程,继续执行后续代码,组装并返回CombinedData。

3. 关键细节:await()与线程释放

  • 任意一个协程(父协程/子协程)调用await()(或任何挂起函数),调用者协程会立即挂起,同时释放当前占用的线程。

  • 线程释放与协程作用域(coroutineScope)无关:coroutineScope仅负责等待所有子协程完成,不管理线程释放;线程释放由「协程挂起」决定。

  • 恢复后线程的归属:若协程绑定Dispatchers.Main(主线程),恢复后必回主线程;若绑定Dispatchers.IO/Default(线程池),恢复后线程可能变化(随机分配线程池中的空闲线程)。

三、协程调度器详解(Dispatchers)

1. 两大核心调度器(Kotlin官方规则)

调度器适用场景最大线程数规则核心特点
Dispatchers.DefaultCPU密集型任务等于CPU核心数(如8核=8个,10核=10个)线程全程占用CPU,多开线程会增加切换开销,降低效率
Dispatchers.IOIO密集型任务max(64, CPU核心数)(绝大多数设备=64)线程99%时间在等待(如网络、文件读写),不占CPU,多开线程提升并发效率

2. 关键补充

  • CPU密集型任务:全程纯计算、不等待,如图片压缩、JSON解析、加密解密、复杂算法运算(必须用Default)。

  • IO密集型任务:主要时间在等待,如网络请求、文件读写、数据库操作(必须用IO)。

  • IO线程上限64的原因:64个线程足够支撑移动端极高并发,再多会浪费内存(线程栈占用)和增加内核切换开销,是行业通用最优值。

四、常见疑问答疑(高频踩坑点)

1. 疑问:启动100个async(IO调度器),线程池不够用会怎样?

解答:不会崩溃、不卡顿、不报错。IO线程池默认上限64,剩余36个协程会进入轻量级等待队列,等有空闲线程(IO线程完成等待、释放线程)后,自动取出执行;排队的协程无内存开销,不占用CPU。

2. 疑问:8核手机IO线程上限64,10核是不是80?

解答:不是。IO线程上限遵循max(64, CPU核心数),只要CPU核心数≤64,无论8核、10核、32核,上限都是64;只有CPU核心数>64(如服务器65核),上限才等于核心数。

3. 疑问:父协程中多个await,需要所有await都调用才释放线程吗?

解答:不需要。只要执行任意一个await(),调用它的协程就会立即挂起、释放线程;后续await()会再次挂起、释放线程,直到所有子协程完成,协程恢复。

4. 疑问:协程挂起(await)后,恢复时一定能回到原来的线程吗?

解答:不一定,看调度器:绑定Dispatchers.Main(主线程),恢复后必回主线程;绑定Dispatchers.IO/Default(线程池),恢复后可能切换到线程池中的其他空闲线程。

五、核心总结(必记)

  • 协程:用户态轻量级任务,依赖线程执行,无线程无法运行;核心优势是「用户态快速切换」和「挂起不阻塞线程」。

  • 并行:协程需依托多线程+多核CPU,同一时刻运行的协程数≤线程数;并发:单线程内协程快速切换,无需多核。

  • 调度器选择:CPU密集用Default(线程数=核心数),IO密集用IO(上限64),主线程操作绑定Main。

  • await():调用即挂起、释放线程,恢复线程由调度器决定;coroutineScope仅负责等待子协程,不管理线程。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 18:59:37

深度学习理论体系:六周完整学习路线图

深度学习理论体系:六周完整学习路线图本文将系统介绍相关知识点,帮助大家快速掌握核心内容。 深度学习是后续学习自然语言处理,强化学习,计算机视觉等细分领域的基础,深度学习的应用也非常广泛,各个学科都会…

作者头像 李华
网站建设 2026/4/14 4:19:16

为什么91%的AIAgent代码生成项目在POC后流产?奇点大会首席架构师亲授“生成-验证-归档”黄金三角工作流(含自动化测试覆盖率阈值表)

第一章:为什么91%的AIAgent代码生成项目在POC后流产? 2026奇点智能技术大会(https://ml-summit.org) AI Agent代码生成项目常在概念验证(POC)阶段展现惊艳效果——自动补全函数、重构遗留模块、甚至生成端到端微服务骨架。然而&a…

作者头像 李华
网站建设 2026/4/15 20:30:18

如何快速掌握Creality Print:3D打印新手的终极切片软件指南

如何快速掌握Creality Print:3D打印新手的终极切片软件指南 【免费下载链接】CrealityPrint 项目地址: https://gitcode.com/gh_mirrors/cr/CrealityPrint Creality Print是一款功能强大的开源3D打印切片软件,专为FDM(熔融沉积成型&a…

作者头像 李华
网站建设 2026/4/14 4:15:09

SpringBoot服务升级总失败?用Jenkins+Nacos做个智能部署看门狗

SpringBoot服务智能部署:JenkinsNacos构建零宕机升级方案 微服务架构下,服务升级如同给飞行中的飞机更换引擎——既要保证系统持续运转,又要确保新版本平稳过渡。传统粗暴的kill -9方式早已无法满足现代分布式系统的稳定性要求,尤…

作者头像 李华