目录
- 总结对比
- 各模型原理简介
- 经典实现
1. 总结对比
| 模型 | 核心机制 | 适合场景 | 复杂度 |
|---|---|---|---|
| 多线程/线程池 | OS 调度 | 计算密集型、小规模并发 | 中 |
| 协程 (Coroutines) | 用户态调度 | 高并发 Web 服务、I/O 密集型 | 低 (开发体验好) |
| 事件驱动 (NIO) | 状态机/回调 | 网关、长连接、代理服务 | 高 |
| Actor(Message Passing) | 消息传递 | 分布式、高可靠、无锁化设计 | 中 |
| Disruptor | 无锁环形队列 | 超高吞吐、极低延迟 (金融/日志) | 极高 |
2. 各模型原理简介
基于多线程的任务并行 (Thread-based / Preemptive Multitasking)
这是最传统、也是你提到的线程池所属的范畴。
- 核心逻辑: 操作系统内核负责线程切换。每个线程有独立的栈空间。
- 优点: 能够充分利用多核 CPU。
- 缺点: 线程是很“重”的资源(通常 1MB 左右),上下文切换(Context Switch)开销大。当并发量达到万级时,内存会爆掉,CPU 也会忙于切换而不是干活。
协作式多任务:协程 (Coroutines / User-level Threads)
这是你提到的第二种,也是目前高并发的主流。
- 核心逻辑: 在用户态调度,而非内核态。协程在遇到 I/O 阻塞时自动让出执行权,而不需要销毁线程。
- 代表: Go (Goroutines), Kotlin (Coroutines), Python (asyncio), Java (Project Loom/Virtual Threads)。
- 特点: 极轻量,单机支持百万级协程不是梦。
事件驱动与非阻塞 I/O (Event-driven / NIO)
这是 Node.js 和 Netty 能够支撑高并发的秘密。
核心逻辑: 使用 I/O 多路复用技术(如 Linux 的
epoll)。程序不再等待 I/O 完成,而是注册一个回调函数(Callback)。当数据准备好时,操作系统通知程序去处理。优点: 单线程也能处理成千上万个连接,资源消耗极低。
缺点: 编程模型复杂(容易陷入回调地狱),不适合 CPU 密集型任务。
Netty
- Redis
Message Passing
Actor模型
这是一种完全不同的思维方式,常见于分布式系统或高可靠应用(如 WhatsApp 的后端)。
- 核心逻辑: 一切皆 Actor。Actor 之间不共享内存,唯一通信方式是发邮件(消息)。
- 优点: 天然无锁。因为不共享变量,所以不存在死锁或竞态条件,扩展性极强。
- 代表: Erlang (OTP), Akka (Scala/Java)。
CSP 模型 (Communicating Sequential Processes)
这是 Go 语言设计的核心理念。
- 核心逻辑: “不要通过共享内存来通信,而要通过通信来共享内存”。
- 工具: Channel(管道)。它与 Actor 类似,但更关注管道本身,生产者和消费者通过管道进行同步。
LMAX Disruptor (无锁环形缓冲区)
如果你追求的是极低延迟的单机高并发(比如高频交易系统),这是顶级方案。
- 核心逻辑: 放弃加锁机制,利用 CPU 缓存行对齐和
CAS(Compare And Swap) 原子操作。它使用一个巨大的环形数组 (Ring Buffer) 在多个线程间传递数据。 - 特点: 消除锁竞争,吞吐量比传统的阻塞队列高出几个数量级。
3. 经典实现
线程池
Java ThreadPool
原理:线程池通过预先创建一定数量的线程,复用这些线程来执行大量短生命周期的任务,避免频繁创建/销毁线程的开销。
核心架构 D2 图示:
优势:
- 线程复用,减少资源消耗
- 支持任务队列、拒绝策略、灵活参数配置
- 适合服务器端、爬虫、批量处理等场景
典型应用:Web 服务器、RPC 框架、异步任务调度
简单代码示例:
ExecutorService pool = new ThreadPoolExecutor(4, 8, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>());
pool.submit(() -> System.out.println("Hello ThreadPool"));
pool.shutdown();
协程
Go Routine
原理:Goroutine 是 Go 运行时调度的用户态线程,创建和切换开销极小。通过 channel 实现 CSP 并发通信。
核心架构 D2 图示:
优势:
- 单机可支持百万级 goroutine
- 语法简单,开发体验好
- 适合高并发、I/O 密集型场景
典型应用:Web 服务、爬虫、分布式系统
简单代码示例:
go func() {
fmt.Println("Hello Goroutine")
}()
事件驱动
Netty
原理:基于 Java NIO,采用 Reactor 事件驱动模型,单线程可处理成千上万连接。
核心架构 D2 图示:
优势:
- 高性能、低延迟
- 支持多种协议和自定义编解码
- 广泛用于 RPC、网关、IM 等
典型应用:分布式系统通信、微服务网关
简单代码示例:
EventLoopGroup boss = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(boss, new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<>() {
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new MyHandler());
}
});
b.bind(8080);
Redis 单线程事件循环
原理:单线程事件循环,I/O 多路复用,极致优化命令处理路径。
优势:
- 代码简单,易于维护
- 单线程避免锁竞争
- 支持高并发连接
典型应用:缓存、消息队列、排行榜等
Actor模型
Akka
原理:基于 Actor 模型,每个 Actor 独立、无共享状态,通过消息传递通信。天然无锁,易于扩展。
核心架构 D2 图示:
优势:
- 易于构建分布式、高可靠系统
- 支持容错、监督、远程通信
- 适合事件驱动、解耦场景
典型应用:IM、分布式任务调度、金融风控
简单代码示例(Scala):
class HelloActor extends Actor {
def receive = {
case msg: String => println(s"Hello $msg")
}
}
val system = ActorSystem("sys")
val actor = system.actorOf(Props[HelloActor])
actor ! "Akka"
Disruptor
LMAX Disruptor
原理:采用无锁环形缓冲区,利用 CAS 原子操作和缓存行填充,极大减少延迟和上下文切换。
核心架构 D2 图示:
优势:
- 极致低延迟,超高吞吐
- 消除锁竞争,适合高频交易
- 适合单机极限性能场景
典型应用:金融高频交易、日志系统、实时数据处理
无锁环形缓冲区,极致低延迟,常用于金融高频交易、日志系统等。