Java Linux NIO性能优化核心是确保JVM启用并高效使用epoll:需检查配置避免降级为poll、全程非阻塞、适配ET模式、合理拆分Selector线程并配合系统参数调优。

Java 在 Linux 下的 NIO 性能优化,核心是让 JVM 真正用上 epoll,并让它高效运转。这不是写底层代码,而是配置、建模和规避常见误用。
确认并加固 epoll 路径
JDK 7+ 默认启用 epoll,但容易被覆盖或降级:
- 检查启动参数,删掉 -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.PollSelectorProvider 这类强制切回 poll 的配置
- 运行时用 jstack 查看 NIO 线程栈,看到 EPollSelectorImpl 或 EPollArrayWrapper#epollWait 才算走对路
- JDK 17+ 可加 -XX:+UseEPoll 显式启用(默认已开,显式更稳妥)
非阻塞必须贯穿全程
epoll 只通知“就绪”,不阻塞线程靠的是 socket 本身非阻塞:
- ServerSocketChannel 创建后立刻调用 configureBlocking(false)
- accept() 返回的每个 SocketChannel,必须立即设为非阻塞——这是最常漏的一步
- read()/write() 必须循环处理,直到返回 -1(连接关闭) 或 0(EAGAIN/EWOULDBLOCK),不能读一次就停
适配边缘触发(ET)语义
Java NIO 在 Linux 上默认使用 ET 模式(由 EPollSelectorImpl 自动适配),这意味着:
立即学习“Java免费学习笔记(深入)”;
- read() 必须读到缓冲区空或 EAGAIN,否则剩余数据不会再次通知
- 推荐用 ByteBuffer.allocateDirect() 减少堆内存拷贝;每次读完调用 compact() 复用 buffer
- 写操作中,OP_WRITE 只在 write() 返回 0(缓冲区满)时才注册,写完立刻取消,避免空转唤醒
线程与 Selector 拆分策略
单个 Selector 能管数万连接,但吞吐受 CPU 核心数限制:
- 按职责拆分:例如 1 个 Selector 专管 accept,2 个分担读写,避免单点瓶颈
- 绝对不在 Selector 线程里做耗时操作(如 JSON 解析、DB 查询)——收到数据后交给业务线程池处理
- 系统级配合:启用 tcp_tw_reuse 缓解 TIME_WAIT;调大 ulimit -n 至 100 万级



















