多线程 Reactor 模式

目录

多线程 Reactor 模式的核心动机

多线程演进方向

多线程 Reactor 模型结构

多线程 EchoServer 实现核心部分

Handler 的多线程化

多线程 Reactor 的三个核心点


本篇文章内容的前置知识为 单线程 Reactor 模式,如果不了解,可点击链接学习
单线程 Reactor 模式-CSDN博客

多线程 Reactor 模式的核心动机

原因:单线程 Reactor 中,Reactor 线程和所有 Handler 处理器都共用同一个线程,一旦某个 Handler 执行时间较长,所有事件的处理都会被阻塞,系统无法横向扩展。
目标:将 Reactor 和 Handler 的职责分离到多个线程中,提高并发能力,适应高连接数和重业务处理场景。

多线程演进方向

(1)升级 Handler:
将负责 IO 读写和业务逻辑的 Handler 放入独立的线程池中异步处理,提高吞吐。
(2)升级 Reactor:
使用多个 Selector,创建多个子反应器(SubReactor),每个负责独立的选择操作。

多线程 Reactor 模型结构

客户端请求
   ↓
Reactor1(主反应器)  →  accept handler(接收连接)
   ↓ 分发给
Reactor2(子反应器)  →  read/decode/compute/encode/write handler

Reactor 1 专职监听新连接事件;
Reactor 2 专职监听 IO 读写事件;
多个 Handler 在不同线程池中处理,互不阻塞。

多线程 EchoServer 实现核心部分

Reactor 主类

Selector[] selectors = new Selector[2];

一个 selector 专管连接接收(OP_ACCEPT);
一个 selector 专管数据读写(OP_READ/WRITE)。

SubReactor subReactor1 = new SubReactor(selectors[0]);
SubReactor subReactor2 = new SubReactor(selectors[1]);

为每个 selector 启动一个线程,轮询事件。

SubReactor 逻辑
子反应器的职责是:
负责轮询 selector 中是否有事件发生;
若有事件触发,就调用 dispatch() 方法,执行 handler。

SelectionKey sk = it.next();
Runnable handler = (Runnable) sk.attachment();
handler.run();

从 selectionKey 中拿出 attach 的 Handler;
直接执行 handler 的 run() 方法。

AcceptorHandler(连接处理器)

SocketChannel channel = serverSocket.accept();
new MultiThreadEchoHandler(selectors[1], channel);

接收连接后创建 IO Handler;
并将其注册到数据读写 selector(selectors[1])中。

Handler 的多线程化

目标:将读写处理逻辑从 IO 事件轮询线程中分离,提交到线程池异步处理。

核心实现:

static ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> asyncRun());

static ExecutorService pool = Executors.newFixedThreadPool(4);
创建一个包含 4 个线程的固定大小线程池,专门用于执行具体的业务逻辑(如数据处理、计算等)。线程池会复用这 4 个线程,避免频繁创建销毁线程的开销。

pool.submit(() -> asyncRun());
将实际的业务处理逻辑(asyncRun() 方法,比如读取数据、回显数据的逻辑)提交到线程池执行。这样做的核心目的是 让 Reactor 线程(负责监听和分发事件)不用等待业务处理完成,可以立即回去处理其他 IO 事件,避免被耗时操作阻塞。

asyncRun() 方法 的代码思路和单线程 Reactor 模式的核心 run() 方法 代码思路类似

单线程 Reactor 模式因 单线程瓶颈,仅适用于简单场景;
Connection Per Thread 因 线程爆炸 问题,已被淘汰;
多线程 Reactor 模式通过 事件分离 + 线程池 解决了前两者的缺陷

多线程 Reactor 的三个核心点

模块处理职责所在线程
Main Reactor监听连接(OP_ACCEPT)主线程
Sub Reactor监听读写事件(OP_READ / OP_WRITE)线程1、线程2(子线程)
Handler(多线程)实际执行 IO + 业务逻辑提交给线程池异步执行

优势对比

模型是否并发是否线程隔离是否支持线程池
单线程 Reactor
多线程 Reactor

Reactor 模式的优缺点

一、Reactor 模式与其他模式对比
(1)Reactor 模式 vs 生产者-消费者模式
相似之处:
二者都具有事件驱动特性。
在生产者-消费者模型中:
生产者产生任务(事件)并放入一个队列。
消费者从队列中拉取(pull)任务并处理。

Reactor 模式下:
客户端连接、读写事件相当于生产者。
Selector 检查事件是否就绪,相当于从“系统缓冲队列”中拉取事件。
Handler 负责处理事件,相当于消费者。

不同之处:
生产者-消费者模型是基于「消息队列」的显式交互;
Reactor 模式是基于 IO 多路复用的「查询式机制」(如 select、epoll)
Reactor 没有明确的队列,而是通过系统底层缓存区查询到事件,再立即由 Dispatcher 分发给对应 Handler 处理。

(2)Reactor 模式 vs 观察者模式
相似之处:
两者都体现了事件监听 + 响应处理的思想。
Reactor 中,Selector 检测到事件 → Dispatcher 分发给对应 Handler。
观察者模式中,主题 Topic 发生变化 → 通知所有订阅该主题的观察者 Observer。
都涉及“注册监听 + 回调响应”的机制。

不同之处:
观察者模式允许一个事件被多个观察者处理(一对多)
而 Reactor 模式中,一个 IO 事件只能交给一个 Handler 实例处理(一对一)
即:事件和处理器的绑定是唯一的,Handler 和 SelectionKey 是一一对应的。

二、Reactor 模式的优点
高响应性:
单线程模式:通过 非阻塞 IO + 事件驱动,避免了传统阻塞 IO 中 一个连接阻塞导致全系统卡住 的问题(仅当 Handler 无阻塞操作时有效)
多线程模式:进一步通过 Reactor 线程与业务线程分离,即使某个业务逻辑阻塞,也不会影响 Reactor 线程处理其他连接,响应性更优。

编程简单:
单线程模式:天然无多线程共享数据问题,不需要锁和同步,逻辑最简洁。
多线程模式:通过 职责分离(Reactor 线程管 IO,业务线程管逻辑),减少了共享数据的场景,相比 一连接一线程 模式,锁和同步的复杂度更低。

良好的可扩展性:
多线程模式:可通过增加 Reactor 线程数(利用多核 CPU)、扩大业务线程池(处理更多并发业务)显著提升吞吐量,扩展性更强。

三、Reactor 模式的缺点
模型实现较复杂:
相较于简单的阻塞 IO,Reactor 涉及 Selector 注册、事件派发、状态管理,门槛较高;
不易调试,错误不易定位。

强依赖系统支持:
依赖于操作系统提供的高效 IO 多路复用机制(如 Linux 的 epoll);
若底层不支持 IO 复用,性能优势无法体现,甚至可能适得其反。

Handler 内部阻塞会影响整体反应能力:
如果某个 Handler 内部业务逻辑阻塞太久(比如读取大文件、等待数据库响应),会导致整个 Selector 线程卡住,从而影响其他 IO 事件的派发,形成伪非阻塞。

模式特点是否规避伪非阻塞?
多 Reactor + 同步 Handler多线程负责 Selector,Handler 仍由 Selector 线程执行不能规避
多 Reactor + 异步 Handler(线程池)Selector 线程只分发事件,Handler 放入线程池处理能完全规避

同步异步handler主要是看它的run方法里面有没有包含耗时/阻塞操作,比如read() / write()

伪非阻塞 指的是表面上使用了非阻塞 IO(如 NIO 的 SocketChannel 配置为非阻塞模式)和 Reactor 事件驱动模型,但由于某个环节(通常是 Handler 处理逻辑)出现阻塞,导致整个 Reactor 线程被卡住,最终失去了非阻塞模式应有的并发处理能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/90634.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/90634.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[NLP]多电源域设计的仿真验证方法

多电源域设计的仿真验证方法 1. 更复杂的 Testbench 例子(多电源域、复杂低功耗场景) 假设有两个电源域 PD1 和 PD2,分别对应控制信号 pwr_sw_ctrl1、iso_ctrl1、ret_ctrl1 和 pwr_sw_ctrl2、iso_ctrl2、ret_ctrl2,且两域之间有通信。 RTL 端口声明(简化版) module top…

Apache Ignite 中 WHERE 子句中的子查询(Subqueries in WHERE Clause)的执行方式

这段内容是关于 Apache Ignite 中 WHERE 子句中的子查询(Subqueries in WHERE Clause)的执行方式 的说明。理解这段内容对于编写高效的 SQL 查询、避免性能瓶颈非常重要。下面我将为你 逐句解释并深入理解这段内容。🧾 原文翻译 解释 原文&a…

MySQL(153)如何使用全文索引?

MySQL的全文索引(Full-Text Index)是一种特殊的索引类型,专门用于加速文本数据的搜索。与普通的B树索引不同,全文索引适用于大文本字段(如TEXT、VARCHAR等)的全文搜索。它通过构建一个倒排索引,…

微分方程入门之入门之入门,纯笔记

当描述 相对变化量 比 绝对量 更容易时,微分方程就经常用到了。 比如,描述为什么种群数量增加or减少【相对】,比描述为什么它在某个时间点是某个特定值【绝对】更容易。 物理学中,运动经常用力来描述,力–>代表变化…

【C++】简单学——vector类(模拟实现)

模拟实现的准备工作 看源码,了解这个类的大概组成 1.先看成员变量 成员变量的组成是三个迭代器 问:这个iterator内嵌类型究竟是什么?即这个迭代器是什么 迭代器实际就是T* 问:这三个迭代器代表什么意思? 连蒙带猜…

【WRF】根据自动安装脚本安装 WRF / WRF-CHEM等

目录 GitHub 上 WRF 自动安装脚本 ⚙️ 脚本的作用 🖥️ 支持的系统 📦 可安装的 WRF 版本及其选项 ✅ 如何使用(以 WRF 4.6.1 为例) ✅ 依赖库的安装位置 完整安装脚本分析 参考 GitHub 上 WRF 自动安装脚本 GitHub 上的 WRF-Install-Script 项目的 Releases(发布版本…

M²IV:面向大型视觉-语言模型中高效且细粒度的多模态上下文学习

MIV: Towards Efficient and Fine-grained Multimodal In Context Learning in Large Vision-Language Models COLM 2025 why 新兴的研究方向:上下文学习(ICL)的效果“向量化”,其核心思想是用transformer内部的向量来…

龙迅#LT8711UXD适用于Type-C/DP1.4 /EDP转 HDMI2.0 功能,分辨率高达4K60HZ,可支持HDCP!

1. 描述LT8711UXD 是一款高性能双通道 Type-C/DP1.4 转 HDMI2.0 转换器,旨在将 USB Type-C 源或 DP1.4 源连接到 HDMI2.0 接收器。该LT8711UXD集成了一个符合 DP1.4 标准的接收器和一个符合 HDMI2.0 标准的发射器。此外,还嵌入了两个用于CC通信的CC控制器…

《计算机组成原理与汇编语言程序设计》实验报告一 基本数字逻辑及汉字显示

目 录 一、实验学时 二、实验目的 三、实验要求 四、实验内容 五、实验步骤 1、打开Logisim软件,列出异或逻辑电路真值表,并使用与、或、非基本原件实现异或逻辑电路。 2、打开Logisim软件,列出同或逻辑电路真值表,并使用…

聚焦牛牛道:绿色积分模式如何实现快速发展?

​绿色消费积分政策再次进入大众视野,这种能为企业减轻库存负担、让咨金周转更灵活的促销方式,很快就成了焦点。牛牛道作为积极践行这一政策的平台,凭借其独树一帜的商业模式和运营思路,在短时间内就取得了显著发展。一、牛牛道平…

高频 RFID 赋能工业教学设备教学应用

高频 RFID 赋能工业教学设备教学应用应用背景传统工业教学设备侧重机械原理、电气控制等基础功能演示,缺乏对 RFID 等工业识别技术的具象教学载体。学生在理论学习中难以直观理解 RFID 技术的工业适配逻辑,实训中缺乏设备识别系统的部署、调试经验&#…

Transformer:颠覆NLP的自注意力革命

Transformer:颠覆NLP的自注意力革命 Transformer是自然语言处理领域中极具影响力的深度学习模型架构,以下是对其的详细介绍: 提出背景与应用:2017年,Vaswani等人在《Attention Is All You Need》论文中首次提出Transformer架构,它主要用于处理序列到序列的任务,如机器翻…

基于 KeepAlived + HAProxy 搭建 RabbitMQ 高可用负载均衡集群

基于 KeepAlived HAProxy 搭建 RabbitMQ 高可用负载均衡集群 基于 KeepAlived HAProxy 搭建 RabbitMQ 高可用负载均衡集群实战指南 一、前言 在企业级应用中,消息队列的高可用性是系统稳定性的重要保障。RabbitMQ 作为主流的消息中间件,虽然自身支持…

京东获得JD商品详情 API 返回值说明||京东API接入文档

京东商品详情API返回值核心字段说明一、商品基础信息商品ID(skuId/productId)唯一标识符,用于定位具体商品或SKU(如不同颜色、尺寸的变体)。示例:"skuId": "123456789"商品标题&#x…

其他世界的自来水

西欧,北美,亚洲日韩等地区,他们的自来水可以直接饮用以英国为例:自来水的质量可能等同或者有可能超过纯净水,不需要消毒和过滤直接可以饮用。直接从水龙接的水和瓶装纯净水没有什么差别,甚至比瓶装纯净水更…

IO密集型、CPU密集型、负载、负载均衡

0、引入 从宏观上来讲,计算机可以抽象为【输入 > 计算 > 输出】这三部分 输入输出自然就是io,而计算部分自然归cpu管 不同的任务,对io和cpu的依赖程度不同,由此有了cpu密集型任务和io密集型任务 1、IO密集型 更依赖输入…

从甲方的角度看MOM项目成败的原因

关键词:MOM、数字化转型、成败数字化转型中流行这么一句话:SAP项目加班到晚上8点,MOM项目最少到晚上10点。由此可见,MOM项目实施的难度、复杂度。但,为什么MOM难度大?先引入1个故事:1个价值300万…

MySQL操作进阶

系列文章目录 MySQL的基础操作-CSDN博客 目录 系列文章目录 前言 一、数据库的约束 1. 约束类型:not null 2. 约束类型:unique 3. 约束类型:default 4. 约束类型:primary key 5. 约束条件:foreign key 二、表…

表征工程 中怎么 调整参数或比例

表征工程 中怎么 调整参数或比例 在表征工程(Representation Engineering)中,调整参数或比例的核心目标是平衡干预效果与模型基础能力,避免过度干预导致语义失真或能力退化。以下是几种常用的方法论及具体案例: 1. 系数缩放法(Scaling Coefficients):通过权重参数控制…

如何使用Anaconda(miniconda)和Pycharm

文章目录前言具体操作Pycharm连接配置 Anaconda(miniconda)创建的虚拟环境PipAnacondaPyCharm三者关系一图胜千言总结前言 本文介绍如何利用Anaconda和Pycharm这两个强大的工具,实现Python项目的高效开发。通过构建虚拟环境、安装依赖包及利…