👉 这是一个或许对你有用 的社群
🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料:
-
《项目实战(视频)》:从书中学,往事中**"练"**
-
《互联网高频面试题》:面朝简历学习,春暖花开
-
《架构 x 系统设计》:摧枯拉朽,掌控面试高频场景题
-
《精进 Java 学习指南》:系统学习,互联网主流技术栈
-
《必读 Java 源码专栏》:知其然,知其所以然

👉这是一个或许对你有用的开源项目
国产Star破10w的开源项目,前端包括管理后台、微信小程序,后端支持单体、微服务架构
RBAC权限、数据权限、SaaS多租户、商城 、支付、工作流、大屏报表、ERP、CRM 、AI大模型、IoT物联网等功能:
【国内首批】支持 JDK17/21+SpringBoot3、JDK8/11+Spring Boot2双版本
一句话结论
Tomcat 支持四种 IO 模型:BIO、NIO、NIO2、APR。从 Tomcat 8 开始,默认是 NIO,99% 的场景不用改。 面试时能把这四种的原理、差异、适用场景说清楚,就算过关。
这道题真正考的不是背名字,而是你对网络通信模型、Tomcat 架构演进、以及性能调优的理解。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
BIO:一个连接一个线程,死等
Tomcat 7 及以前的默认模型。
工作方式像"一对一服务":Acceptor 接收到连接后,为每个 Socket 分配一个工作线程。这个线程从读请求到写响应全程占用,中间网络慢就干等着,线程被阻塞,CPU 却在空转。
问题很明显: 线程池满了就拒绝新连接。并发能力完全受限于线程数。要支撑 1000 个并发连接,就得开 1000 个线程,内存和上下文切换费用大得离谱。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
NIO:多路复用,一个线程盯一堆连接
Tomcat 8+ 的默认模型,也是目前的主流选择。
核心是 多路复用器 Selector 。少量的 Poller 线程通过 Selector 监听大量 Channel,只有某个 Channel 真正有 I/O 事件(读就绪、写就绪)时,线程才去处理。没事做的连接不占线程,这就是性能飞跃的根本原因。
打个比方:BIO 是每个客人配一个服务员的高端覿店,NIO 是一个服务员同时看 20 张桌子的快餐店------谁举手服务谁,不举手的不浪费人力。
APR:绕过 JVM,直接跟内核对话
通过 JNI 调用本地库,绕过 Java NIO 层,直接和操作系统内核交互。
它利用了 epoll(Linux)、kqueue(BSD)等高效事件通知机制,内存管理也绕过了 JVM 堆,支持零拷贝。理论上这是性能天花板。
但明显的代价是部署复杂度。 需要安装 APR 本地库,依赖操作系统环境,Docker 化部署也得额外处理。它的优势主要体现在静态资源处理 (图片、大文件下载)和底层网络操作上,对纯动态内容的提升并不明显。
NIO2:听起来很美,用得很少
NIO2 即 AIO(异步 I/O),理论上比 NIO 更进一步------不用你主动轮询,操作系统完成 I/O 后直接回调通知你。
但现实很骨感: Linux 对真正的 AIO 支持一直不完善(尤其是网络 I/O 场景),NIO 的 epoll 已经足够高效,所以 NIO2 在生产环境里几乎没人用。它更像是一个"技术上存在,工程上无感"的选项。
一张表看懂四种模型的差异
| BIO | NIO(默认) | APR | NIO2 | |
|---|---|---|---|---|
| 实现 | 纯 Java,同步阻塞 | 纯 Java,Selector 多路复用 |
JNI 调用本地库 | 纯 Java,异步回调 |
| 线程模型 | 1 连接 = 1 线程 | 少量线程管理大量连接 | 本地事件驱动 | 异步回调 |
| 并发能力 | 低 | 高 | 极高 | 理论高,实际不确定 |
| 部署 | 简单 | 简单 | 复杂(需本地库) | 简单 |
| 适合场景 | 低并发老项目 | 绝大多数 Web 应用 | 静态资源为主的场景 | 基本不用 |
选型结论:默认 NIO 不动,静态资源多考虑 APR,BIO 和 NIO2 忘了就行。
怎么配置:server.xml 里改一行的事
在 server.xml 的 Connector 里改 protocol 属性即可:
go
<!-- NIO(Tomcat 8+ 默认,不写也是这个) -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000" redirectPort="8443" />
<!-- NIO2 -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000" redirectPort="8443" />
<!-- APR(需要先装库) -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
connectionTimeout="20000" redirectPort="8443" />
实际项目中,更常见的调优是调 maxConnections 和 maxThreads 这些参数,而不是换 IO 模型。
三个常见误区,面试少说少失分
误区一:"Tomcat 性能差,高并发得换 Netty"。 对于标准的 HTTP 请求响应式 Web 服务(Spring MVC 应用),Tomcat NIO 的性能完全能打。Netty 的优势在于自定义协议和更精细的网络控制,主要用在 RPC、即时通信等场景。别一上来就拿 Netty 打压 Tomcat。
误区二:"用了 NIO 就不会阻塞了"。 NIO 解决的是 I/O 等待的阻塞 。但你的业务逻辑里有慢 SQL、重计算、长时间的 RPC 调用?工作线程照样被堵。IO 模型解决不了业务层面的性能问题。
误区三:"APR 无论如何都比 NIO 快"。 APR 的优势集中在静态资源和底层网络操作。对于纯动态内容的 Java 应用,提升很小,但部署复杂度确实派上来了。不压测就下结论,都是猎人。
欢迎加入我的知识星球,全面提升技术能力。
👉 加入方式,"长按 "或"扫描"下方二维码噢:

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。





go
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)