在现代开发中,我们越来越多地写出这样的代码:

看起来是同步调用,但它们却是并发执行的。
再看 Java:

也是同步写法,但在虚拟线程下,同样可以并发运行。
这就引出了一个很有意思的问题:
👉 为什么代码是"同步的",执行却是"异步的"?
围绕这个现象,JVM 生态走出了两条不同的路径:
- Java 虚拟线程(Virtual Threads)
- Kotlin 协程(Coroutines)
它们都在做同一件事:
让你用同步的方式,写出异步的代码
但实现方式,却完全不同。
🧪 实验场景
统一场景:
并发请求 WanAndroid 接口,然后汇总输出结果
1. 先看我的两份对照代码在做什么
Java 版:虚拟线程 + 阻塞式 Retrofit
Java 示例的核心逻辑是:

真正执行请求时,用的依然是 Retrofit 的阻塞式调用:

也就是说,这套写法本质上还是同步阻塞风格,只不过任务跑在虚拟线程里。
Kotlin 版:协程 + suspend Retrofit
Kotlin 示例的核心逻辑是:

对应的 Retrofit 接口定义是:

这里的特点很明显:
- API 本身就是
suspend - 并发通过
async - 汇总通过
await - 外层由
coroutineScope统一管理
2. Java 虚拟线程是什么
Java 21 正式发布了虚拟线程,这是 Project Loom 最重要的成果之一。
传统平台线程直接映射到操作系统线程,创建和切换成本都比较高。
如果我们有大量 I/O 阻塞任务,比如网络请求、数据库访问、文件读写,那么很容易出现:
- 线程数越来越多
- 很多线程都在"等"
- 系统资源被大量线程占住
虚拟线程的思路是:
- 开发者继续按线程模型写代码
- JVM 在底层负责调度这些轻量线程
- 当虚拟线程发生阻塞时,JVM 可以把它从 carrier thread 上卸下来
- 让底层平台线程继续执行其他任务
所以虚拟线程的关键价值是:
保留阻塞式编程模型,但把线程成本降下来。
这点和我 Java 示例里的写法非常一致:
- 还是
Callable - 还是
Future - 还是
call.execute() - 只是执行器换成了
newVirtualThreadPerTaskExecutor()
3. Kotlin 协程是什么
Kotlin 协程是语言和库层面的并发抽象。
它不是线程,也不是简单的线程池封装。
协程更关心的是:
- 哪些地方可以挂起
- 哪些任务要并发
- 任务之间的父子关系是什么
- 异常和取消怎么传播
- 生命周期怎么管理
在我的 Kotlin 示例里,api.banner() 和 api.homeArticles() 都是 suspend fun。
这意味着它们在语义上就是"可挂起"的操作,而不是普通阻塞函数。
所以协程的核心价值不是"线程更便宜",而是:
让异步流程在代码层就具备结构化表达能力。
4. 它们的相同点:都能把并发 API 调用写得更自然
虽然虚拟线程和协程本质不同,但在并发 API 调用这个场景里,它们的目标是一致的。
4.1 都适合 I/O 密集型任务
比如:
- HTTP 请求
- 数据库查询
- 文件读取
- 消息队列消费
这类任务共同特点是:等待时间远大于计算时间。
无论虚拟线程还是协程,都非常适合这种场景。
4.2 都能让代码接近同步思维
Java 版中,业务逻辑看起来依然是同步代码:

Kotlin 版中,调用看起来也很自然:

这其实是两种技术都非常吸引人的地方:
- 不需要写复杂回调
- 不需要把业务逻辑切碎
- 并发代码可读性明显更好
4.3 都能显著提升并发吞吐能力
无论是虚拟线程还是协程,它们本质上都在提升 I/O 等待期间的资源利用率。
所以如果你的服务瓶颈主要在 I/O,而不是 CPU 计算,两者都可能带来明显收益。
5. 它们最大的不同点:解决问题的层次不同
Java 虚拟线程和 Kotlin 协程都想解决同一类问题:让你用"看起来同步"的代码写高并发 I/O,避免传统平台线程太贵。但它们的抽象层级和调度模型不同。
Java 虚拟线程解决的是"线程太贵",Kotlin 协程解决的是"异步任务怎么组织和治理"。
5.1 虚拟线程更像"线程模型升级"
从我的 Java 代码就能看出来:
- 任务仍然是线程任务
- 结果仍然是
Future - 请求仍然是阻塞式调用
- 并发依然通过 Executor 调度
所以虚拟线程并没有改变你的业务编程范式。
它做的是:在底层把线程变轻。
这对 Java 服务端尤其友好,因为可以低成本承接大量已有阻塞代码。
5.2 协程更像"并发治理模型升级"
而 Kotlin 协程从写法上就已经体现出另一种思路:
suspendcoroutineScopeasyncawait
这些 API 不只是"把任务跑起来",还在表达:
- 任务边界
- 生命周期边界
- 取消边界
- 异常传播边界
所以协程的重点是:
不仅要能并发,还要能把并发任务管清楚。
6. 虚拟线程保留了阻塞语义
很多人第一次接触虚拟线程时,很容易说出一句话:
"虚拟线程让阻塞调用变成非阻塞了。"
这个说法并不准确。
拿我 Java 示例里的代码来说:
这仍然是阻塞调用。
语义没有改变。
更准确的说法应该是:
虚拟线程没有改变阻塞语义,它只是把阻塞的代价大幅降低了。
也就是说:
Thread.sleep()还是阻塞BlockingQueue.take()还是阻塞- JDBC 查询还是阻塞
- Retrofit 的
execute()还是阻塞
只是这些阻塞如果发生在虚拟线程里,JVM 可以把虚拟线程从 carrier thread 上卸下来,让底层平台线程去干别的活。
所以:
- 阻塞没有消失
- 只是不会再昂贵地占住平台线程
而 Kotlin 协程这边,很多操作在语义上就是"挂起"而不是"阻塞线程",这就是两者很本质的差异。
7. 结构化并发:Kotlin 协程真正稍强
如果只是发两个并发请求,你可能会觉得两者差不多。
但一旦业务复杂起来,差距就会慢慢显现。
比如:
- 一个子任务失败了怎么办
- 页面关闭时任务怎么取消
- 超时后其他任务要不要停
- 任务是不是属于同一个生命周期
Kotlin 协程从设计上就强调结构化并发。
像我 Kotlin 示例里的:

这意味着子任务都属于这个作用域,生命周期边界非常清晰。
而 Java 虚拟线程本身并不天然等于结构化并发。
Java 虽然也有 StructuredTaskScope,但那是另一层 API,不等于"只要用了虚拟线程,就自动拥有协程式的结构化语义"。
所以这部分可以总结成一句话:
虚拟线程偏执行模型,协程偏任务治理模型。
8. Android 上怎么选
这一部分基本是最现实的答案。
8.1 当前 Android 的主流答案仍然是协程
原因很简单,因为 Android 生态已经围绕协程形成了完整配套:
viewModelScopelifecycleScopeFlowRoomPagingWorkManager
也就是说,在 Android 里,协程不是一个孤立的并发工具,而是一整套工程能力的一部分。
所以如果你今天在写 Android 项目,默认选择仍然应该是:
优先使用 Kotlin 协程。
8.2 Android 目前还没有真正实现虚拟线程
截至 目前,Android 官方 Thread 文档中 isVirtual() 的说明明确指出:
This method always returns false because virtual thread isn't implemented on Android yet.
这句话非常关键,说明两点:
- Android API 层已经出现了相关接口
- 但 Android 运行时当前还没有真正实现虚拟线程
所以如果有人问:
"Android 现在能不能直接像标准 JDK 21 一样用 Loom 虚拟线程?"
答案是:
还不能。
9. Android 的未来会怎样
这部分不适合说得太满,但可以做一个稳妥判断。
9.1 Android 不会完全忽略 Loom
既然已经有 isVirtual() 这样的 API 入口,就说明 Android 至少在接口层面已经考虑了兼容问题。
这意味着 Loom 不是一个完全与 Android 无关的方向。
9.2 但中短期内,协程地位依然很稳
因为现在 Android 的上层生态已经深度绑定协程:
- 官方推荐方案是协程
- Jetpack 组件大量围绕协程设计
- 真实项目中,协程已经是主流并发抽象
所以更合理的判断不是"协程会不会被虚拟线程替代",而是:
未来 Android 可能逐步吸收 Loom 能力,但上层主要并发抽象很可能依旧是协程。
也就是说,未来最可能出现的是"分层协同",而不是"二选一替换"。
10. 该怎么选
如果你是 Java 服务端开发者,而且项目里已经有大量阻塞式调用:
- JDBC
- 同步 HTTP Client
- 传统 DAO/Service 结构
- 线程池 + Future 模型
那么虚拟线程是非常值得关注的选择,因为它迁移成本低、收益直接。
如果你是 Kotlin / Android 开发者,尤其在做:
- 页面生命周期管理
- UI 状态更新
- Flow 数据流
- ViewModel + Repository 架构
那么协程仍然是更自然、更成熟的方案。
11. 总结
回到我项目里的两份代码:
它们已经很好地说明了这件事:
相同点
- 都适合并发 I/O
- 都能让代码比传统回调更清晰
- 都能提升高并发场景下的吞吐能力
不同点
- Java 虚拟线程:让阻塞式代码重新变轻
- Kotlin 协程:让异步任务从一开始就更结构化、更可管理
Android 未来
- 截至目前,Android 仍未真正实现虚拟线程
- 当前 Android 主流并发方案仍然是协程
- 未来更可能是 Loom 能力逐步下沉,而协程继续作为上层主要抽象存在