不止是“房子”与“工人”:Android 并发与隔离的架构之道

167 阅读4分钟

一句话总结:

协程、线程、进程构成了 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 应用。