一句话总结:
协程、线程、进程构成了 Android 并发与隔离的“三级火箭”。协程是处理异步任务的“默认引擎”,线程是需要精细控制时的“助推器”,而多进程则是为了突破内存或稳定性瓶颈时,才启动的、成本高昂的“星际引擎”。
第一章:基本概念——那栋“房子”和里面的“工人”
- 进程 (Process): 操作系统进行资源分配和调度的独立单元。核心特性是内存隔离。
- 线程 (Thread): CPU 调度的最小单元,它寄生于进程之中。核心特性是共享进程的内存空间。
| 特性 | 进程 | 线程 |
|---|---|---|
| 隔离性 | ✅ 内存、数据完全隔离 | ❌ 共享内存,数据需同步 |
| 开销 | 高 (创建/销毁成本高) | 低 (创建/销毁成本低) |
| 通信 | 复杂 (需 IPC 机制) | 简单 (直接读写共享变量) |
第二章:现代 Android 的“并发工具谱系”
在做架构决策时,我们不应只考虑“线程”和“进程”,而应在一个更广的谱系中选择。
| 工具 | 隔离级别 | 并发模型 | 成本 | 核心场景 |
|---|---|---|---|---|
| 协程 (Coroutine) | 无隔离 | 协作式调度 (非抢占) | 极低 | 95% 的异步任务,如网络请求、UI 交互 |
| 线程 (Thread) | 无隔离 | 抢占式调度 (OS 级) | 中等 | 需要与 Native 代码交互、或实现精细化线程控制的场景 |
| 进程 (Process) | ✅ 完全隔离 | 抢占式调度 (OS 级) | 极高 | 需要突破内存上限、隔离风险、保证核心服务稳定的场景 |
结论: 在 Kotlin-First 的今天,协程是你的“默认武器” 。只有当协程无法满足需求时,才考虑下沉到更原始的“线程”。而“多进程”,则是一项需要被严格评估、非到万不得已不动用的“战略级武器”。
第三章:战略抉择——何时应该开启“多进程”这台“星际引擎”?
开启一个新进程的成本是高昂的(额外的内存占用、复杂的 IPC 开销)。因此,你必须有足够充分的理由。以下是三个最常见的“正当理由”:
1. 突破内存天花板
- 问题: Android 为每个进程分配的堆内存(Heap Size)是有限的。当你的某个功能模块(如高清图片编辑器、视频渲染引擎)需要消耗远超这个限制的内存时,就会导致主进程 OOM。
- 解决方案: 将这个“内存巨兽”功能放到一个独立的
:webview或:editor进程中,操作系统会为它分配一套全新的、独立的内存空间。
2. “隔离”风险源
- 问题: 你的应用需要集成一个庞大、复杂、且可能存在稳定性问题的第三方 SDK(尤其是包含大量 C++ 代码的)。
- 解决方案: 将这个 SDK 的所有初始化和调用,都封装在一个独立的
:third_party进程中。这样,即使 SDK 内部发生崩溃或内存泄漏,也只会摧毁这个“沙箱”进程,而不会波及你的主应用进程。
3. 保证核心服务的“绝对存活”
- 问题: 你的应用有一个核心的后台服务(如音乐播放、文件上传),你希望即使用户界面的主进程因为某个 Bug 崩溃了,这个后台服务也能继续运行。
- 解决方案: 将这个
Service声明在独立的:service进程中。这样,主进程的崩溃将与它无关,保证了核心任务的连续性。
第四章:战术细化——为你的“打工人”(线程)精细分工
即使是在进程内部,也并非所有“后台任务”都一样。将任务精细分类,并交给合适的“工种”处理,是线程优化的关键。
- I/O 密集型任务: 使用
Dispatchers.IO。 - CPU 密集型任务: 使用
Dispatchers.Default。
通过这种方式,我们确保了“等待”的任务不会长时间霸占宝贵的 CPU 计算资源,而“计算”的任务也不会因为线程过多而导致性能下降。
结论:
“进程”和“线程”不再仅仅是两个需要背诵定义的计算机科学名词,而是 Android 架构师工具箱中,处于不同成本和能力维度的**“架构组件”**。理解它们的本质区别、能力边界和战略价值,并结合协程等现代工具,才能构建出真正稳定、高效、可扩展的现代化 Android 应用。