I/O 的概念
I/O(Input/Output)指输入输出操作,是程序与外部设备(如磁盘、网络、键盘等)交互的过程。核心目标是实现数据的高效读写,分为磁盘 I/O、网络 I/O 等类型。
同步 vs 异步、阻塞 vs 非阻塞
同步/异步:关注任务完成的通知机制。同步需等待任务完成,异步通过回调或事件通知。
阻塞/非阻塞:关注等待时的线程状态。阻塞会挂起线程,非阻塞立即返回状态。
示例:
- 同步阻塞:读取文件时线程阻塞直到数据就绪。
- 异步非阻塞:通过回调通知数据就绪,线程可处理其他任务。
BIO(Blocking I/O)
BIO 是同步阻塞模型,每个连接需独立线程处理。线程在读写时阻塞直到操作完成。
示例:
ServerSocketserverSocket=newServerSocket(8080);while(true){Socketsocket=serverSocket.accept();// 阻塞newThread(()->handleRequest(socket)).start();}NIO(Non-blocking I/O)
NIO 是同步非阻塞模型,通过 Selector 监听多个 Channel 的事件(如读写就绪),避免线程阻塞。
核心组件:
- Channel:双向数据传输通道。
- Buffer:数据容器。
- Selector:多路事件监听器。
示例:
Selectorselector=Selector.open();channel.configureBlocking(false);channel.register(selector,SelectionKey.OP_READ);while(true){selector.select();// 阻塞直到事件就绪Set<SelectionKey>keys=selector.selectedKeys();// 处理事件...}AIO(Asynchronous I/O)
AIO 是异步非阻塞模型,操作系统完成 I/O 后主动回调,无需线程轮询。
核心类:
- AsynchronousSocketChannel
- CompletionHandler
示例:
AsynchronousServerSocketChannelserver=AsynchronousServerSocketChannel.open();server.bind(newInetSocketAddress(8080));server.accept(null,newCompletionHandler<AsynchronousSocketChannel,Void>(){@Overridepublicvoidcompleted(AsynchronousSocketChannelclient,Voidattachment){// 处理连接...}});Netty 简介
Netty 是基于 NIO 的高性能网络框架,提供事件驱动、零拷贝等特性,简化 NIO 编程。
核心优势:
- 线程模型优化(如主从 Reactor)。
- 解决粘包/半包问题(如 LengthFieldBasedFrameDecoder)。
BIO、NIO、AIO 的区别
| 特性 | BIO | NIO | AIO |
|---|---|---|---|
| 模型 | 同步阻塞 | 同步非阻塞 | 异步非阻塞 |
| 线程开销 | 高(1连接1线程) | 低(多路复用) | 极低(回调驱动) |
| 适用场景 | 低并发 | 高并发短连接 | 高并发长连接 |
Java IO 流分类
- 按方向:
- 输入流(InputStream/Reader)
- 输出流(OutputStream/Writer)
- 按单位:
- 字节流(操作二进制数据)
- 字符流(处理文本,如 FileReader)
内核空间
内核空间是操作系统核心代码的运行区域,用户程序需通过系统调用(如read())访问硬件资源。I/O 操作本质是数据在用户空间与内核空间之间的拷贝。
五种 I/O 模型
- 阻塞 I/O
- 非阻塞 I/O
- I/O 多路复用(如 select/poll/epoll)
- 信号驱动 I/O
- 异步 I/O(如 AIO)
Bit、Byte、Char 的区别
- Bit:二进制最小单位(0/1)。
- Byte:8 bits,存储基本数据类型(如
byte)。 - Char:16 bits(Java 中),表示 Unicode 字符。
对象序列化与反序列化
序列化:将对象转换为字节流(如网络传输或持久化)。
反序列化:将字节流恢复为对象。
示例:
ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream("data.obj"));oos.writeObject(myObject);// 序列化serialVersionUID 的作用
用于版本控制,确保序列化与反序列化的类兼容。未显式定义时,JVM 自动生成,但类结构变化可能导致反序列化失败。
生成方式:
privatestaticfinallongserialVersionUID=1L;// 手动指定BufferedReader
属于字符缓冲流,提升读取效率。
常用方法:
readLine():读取一行文本。close():关闭流。
Java IO 流顶级超类
- 字节流:
InputStream、OutputStream - 字符流:
Reader、Writer
图片/视频必须用字节流
媒体文件是二进制数据,字符流可能因编码转换损坏内容。字节流(如FileInputStream)直接操作原始字节。
BIO 服务端为何多线程
单线程处理连接时会阻塞,无法并发响应。多线程允许同时处理多个客户端请求,但线程开销大(C10K 问题)。
多线程 BIO 瓶颈
- 线程创建/销毁成本高。
- 线程数过多导致上下文切换频繁,CPU 利用率下降。
线程池能否彻底解决 BIO
不能。线程池仅缓解线程创建开销,但高并发时仍受限于线程数量(如池满后请求排队)。
NIO 核心组件
- Channel:数据传输管道(如
SocketChannel)。 - Buffer:数据容器(如
ByteBuffer)。 - Selector:监听多个 Channel 的事件。
Buffer 重要属性
capacity:缓冲区容量。position:当前读写位置。limit:可操作数据边界。flip():切换读写模式。
Selector 工作原理
通过系统调用(如epoll)监听注册的 Channel,当 I/O 事件(如读就绪)发生时,返回可处理的 SelectionKey 集合。
NIO 编程难点
- 事件处理逻辑复杂(需管理 Buffer、Channel 状态)。
- 需处理半包/粘包问题(如自定义编解码器)。
AIO 核心类
AsynchronousFileChannel:异步文件操作。AsynchronousSocketChannel:异步网络通信。
Netty 线程模型
主从 Reactor 模式:
- BossGroup:处理连接请求。
- WorkerGroup:处理 I/O 事件。
- 每个 Channel 绑定到固定 EventLoop 避免竞争。
Netty 解决粘包/半包
- 固定长度解码器(
FixedLengthFrameDecoder)。 - 分隔符解码器(
DelimiterBasedFrameDecoder)。 - 长度字段解码器(
LengthFieldBasedFrameDecoder)。
Netty 零拷贝
- Direct Buffer:避免 JVM 堆与 Native 内存拷贝。
- CompositeByteBuf:合并多个 Buffer 减少拷贝次数。
- 文件传输:通过
FileRegion直接发送文件。
Netty 心跳机制
使用IdleStateHandler检测空闲连接:
pipeline.addLast(newIdleStateHandler(30,0,0,TimeUnit.SECONDS));pipeline.addLast(newHeartbeatHandler());ChannelPipeline
责任链模式,包含一系列 ChannelHandler,按顺序处理入站/出站事件。示例:
pipeline.addLast(newDecoderHandler());pipeline.addLast(newBusinessLogicHandler());Linux 底层支持
- BIO:基于系统调用
read()/write()。 - NIO:基于
epoll(高效多路复用)。 - AIO:依赖 Linux 的
io_uring或 glibc 的线程池模拟。
Netty 不直接用 AIO
- Linux AIO 对非文件 I/O 支持不完善。
- NIO(epoll)已满足高性能需求,且更稳定。
优化 Netty 性能
- 调整 EventLoopGroup 线程数(通常为 CPU 核数 * 2)。
- 使用对象池(如
Recycler)减少 GC 压力。 - 开启 Native EPoll(
EpollEventLoopGroup)。
Netty 内存泄漏排查
- 启用
ResourceLeakDetector:System.setProperty("io.netty.leakDetection.level","PARANOID"); - 检查未释放的 ByteBuf 或 Channel。
Netty 应用案例
- Dubbo:RPC 框架。
- RocketMQ:消息队列。
- Elasticsearch:分布式搜索。
- Spring WebFlux:响应式 Web 框架。