Java NIO 学习小记 :Buffer、Channel 与 Selector
在 Java 的 I/O 体系中,NIO(New Input/Output)是对传统 BIO(Blocking I/O)的优化。NIO 提供了更高效的 面向缓冲区、基于通道 的数据处理方式,并且通过 多路复用器(Selector) 实现了单线程处理多个连接的能力。本文简单记录 NIO 的核心概念与常用方法。
一、NIO 的三大核心组件
1. Buffer(缓冲区)
Buffer 是 NIO 中存储数据的容器,底层是数组,但提供了更强大的数据操作能力。所有读写操作都需要通过 Buffer。
常见类型:
ByteBuffer
(最常用,网络传输、文件读写)CharBuffer
IntBuffer
LongBuffer
DoubleBuffer
FloatBuffer
ShortBuffer
核心方法:
put()
:写入数据到缓冲区get()
:从缓冲区读取数据flip()
:写模式切换为读模式clear()
:清空缓冲区(仅重置指针,不清除数据)rewind()
:回到开头重新读取mark()
/reset()
:标记和回滚remaining()
:返回可读数据量
2. Channel(通道)
Channel 类似于传统的流(Stream),但支持双向操作(可读可写),并且必须配合 Buffer 使用。
常见实现:
FileChannel
:文件 I/OSocketChannel
:TCP 客户端ServerSocketChannel
:TCP 服务端DatagramChannel
:UDP 通信
常用方法:
read(ByteBuffer buffer)
:从通道读入数据到 Bufferwrite(ByteBuffer buffer)
:从 Buffer 写数据到通道close()
:关闭通道open()
:打开通道(如FileChannel.open()
)
3. Selector(选择器)
Selector 是 NIO 的核心,用于管理多个通道,支持非阻塞 IO。通过一个线程就能高效处理成百上千的连接。
常用方法:
open()
:打开一个选择器select()
:阻塞直到有通道就绪selectNow()
:非阻塞立即返回selectedKeys()
:获取就绪通道集合register(channel, ops)
:注册通道并监听事件
事件类型:
OP_ACCEPT
:连接就绪OP_CONNECT
:连接建立OP_READ
:可读OP_WRITE
:可写
二、NIO 的 I/O 模型
- BIO(同步阻塞):一个连接一个线程,效率低。
- NIO(同步非阻塞):一个线程管理多个连接,配合 Selector 实现多路复用。
- AIO(异步非阻塞):Java 7 引入,基于回调机制,I/O 完成后自动通知。
三、例子
1. FileChannel + Buffer 示例
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class NIOFileExample {public static void main(String[] args) throws Exception {RandomAccessFile file = new RandomAccessFile("test.txt", "rw");FileChannel channel = file.getChannel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = channel.read(buffer);while (bytesRead != -1) {buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}buffer.clear();bytesRead = channel.read(buffer);}channel.close();file.close();}
}
2. Selector 示例(简易 TCP 服务端)
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;public class NIOServer {public static void main(String[] args) throws Exception {Selector selector = Selector.open();ServerSocketChannel server = ServerSocketChannel.open();server.bind(new InetSocketAddress(8080));server.configureBlocking(false);server.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();Iterator<SelectionKey> keys = selector.selectedKeys().iterator();while (keys.hasNext()) {SelectionKey key = keys.next();keys.remove();if (key.isAcceptable()) {SocketChannel client = server.accept();client.configureBlocking(false);client.register(selector, SelectionKey.OP_READ);System.out.println("客户端连接:" + client.getRemoteAddress());} else if (key.isReadable()) {SocketChannel client = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int len = client.read(buffer);if (len > 0) {buffer.flip();System.out.println("收到消息:" + new String(buffer.array(), 0, len));client.write(ByteBuffer.wrap("已收到\\n".getBytes()));}}}}}
}
四、总结
- Buffer:数据容器,提供丰富的操作方法。
- Channel:数据通道,配合 Buffer 使用。
- Selector:多路复用器,非阻塞 IO 的关键。
NIO 提供了比 BIO 更高效的方式来处理网络和文件 I/O,是理解 Netty 等高性能网络框架的基础。