并发模型
线程/协程/actor;对照 java-fundamentals。
30 分钟
并发模型
后端「快」往往来自 并行处理请求,而非单行代码更快。各语言对并发的抽象不同:OS 线程、协程、Actor、事件循环——理解模型,才能 debug 死锁、泄漏与 tail latency。本节对照 java-fundamentals 线程世界与 Go/Rust/Node 的做法。
学习目标
- 区分线程、协程(goroutine/fiber)、Actor、事件循环
- 说清 Java 平台线程、虚拟线程与 Go goroutine 的异同直觉
- 知道跨语言服务里 并发在进程内,一致性在边界外
四种常见模型
1. OS 线程 + 锁(经典 Java)
ExecutorService pool = Executors.newFixedThreadPool(32);
pool.submit(() -> callExternalApi());
java.util.concurrent、 synchronized、 ReentrantLock。虚拟线程(Project Loom)降低阻塞 I/O 的线程成本,写法仍像同步代码。
2. 协程 / 轻量任务(Go)
go handleRequest(conn) // 成千上万个 goroutine
M:N 调度,channel 传递数据。注意:不要阻塞在无人消费的 channel 上。
3. async/await + 事件循环(Node、Rust Tokio、C#)
node-async:单线程处理 I/O 回调,CPU 重活要放 Worker 或另起服务。Rust/C# 的 async 是 状态机 + 线程池,语义接近但无 GIL 问题。
4. Actor(Akka、Erlang 传统、部分 Orleans)
邮箱 + 单线程处理消息,避免共享可变状态。Java 侧 Akka/Pekko;与 spring-cloud-essentials 微服务 进程级隔离 可组合:Actor 进程内,Service 进程间。
对照表
| Java(现代) | Go | Node.js | Rust async | |
|---|---|---|---|---|
| 默认单位 | Thread / Virtual Thread | goroutine | callback/Promise | Future |
| 通信 | 共享内存+JUC | channel | 事件、消息 | channel/mpsc |
| 阻塞 I/O | VT 友好 | 阻塞仍占 OS 线程 | 忌 sync CPU | .await |
| 调试 | jstack、JFR | pprof, trace | --inspect | tokio-console |
跨语言微服务里的「并发」
单服务内选模型;服务间用 HTTP/gRPC/消息队列。不要在 Java 里用共享内存去「优化」本该走 grpc-streaming 的流式场景。