一、核心机制深度解析
- BIO (Blocking I/O - 阻塞式 I/O)
-
- 基础: 基于流(Stream)。
InputStream/OutputStream处理字节,Reader/Writer处理字符。 - 模型: 同步阻塞。线程在读/写操作完成前一直被挂起。
- 瓶颈: 高并发时需大量线程,线程创建/切换开销巨大,资源利用率低。
- 场景: 连接数少、逻辑简单。
- 基础: 基于流(Stream)。
- NIO (New I/O / Non-blocking I/O - 新 I/O / 非阻塞 I/O)
-
- 核心三剑客:
-
-
- Buffer: 数据容器(
ByteBuffer,CharBuffer等),提供高效读写方法。 - Channel: 连接源(文件、套接字)的双向通路(
FileChannel,SocketChannel,ServerSocketChannel)。数据总是先读入 Buffer 或从 Buffer 写出。 - Selector: 单线程监听多个 Channel 的 I/O 事件(连接就绪、读就绪、写就绪),实现多路复用。
- Buffer: 数据容器(
-
-
- 模型: 同步非阻塞。线程发起 I/O 请求后立即返回,通过 Selector 轮询就绪事件再处理,避免线程阻塞。
- 优势: 单线程可管理大量连接,极大提升并发能力和资源利用率。
- 场景: 高并发网络应用(聊天服务器、游戏服务器)。
- NIO.2 (Java 7+ - 真正的异步 I/O 基础)
-
- Path 与 Files: 替代笨拙的
File类,提供丰富、便捷的文件系统操作。 - AsynchronousFileChannel: 支持异步文件 I/O,操作完成后回调通知。
- AsynchronousSocketChannel: 支持异步套接字 I/O。
- 优势: 文件操作更现代简洁;提供真正的异步 I/O (AIO) 支持(基于回调或 Future),进一步释放线程资源。
- Path 与 Files: 替代笨拙的
二、关键示例代码
示例 1:BIO 文件复制 (效率较低)
try (InputStream is = new FileInputStream("source.txt");
OutputStream os = new FileOutputStream("dest_bio.txt")) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) { // 阻塞点
os.write(buffer, 0, bytesRead); // 阻塞点
}
}
示例 2:NIO 文件复制 (更高效,利用 Channel 和 Buffer)
try (FileInputStream fis = new FileInputStream("source.txt");
FileOutputStream fos = new FileOutputStream("dest_nio.txt");
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel()) {
ByteBuffer buffer = ByteBuffer.allocateDirect(1024); // 可分配直接缓冲区(更快)
while (inChannel.read(buffer) != -1) { // 非阻塞模式下可能读0字节,此处简化
buffer.flip(); // 切换为读模式
outChannel.write(buffer); // 写入
buffer.clear(); // 清空/切换为写模式
}
}
示例 3:NIO.2 文件复制 (简洁现代)
Path source = Paths.get("source.txt");
Path dest = Paths.get("dest_nio2.txt");
Files.copy(source, dest, StandardCopyOption.REPLACE_EXISTING); // 一行搞定!
示例 4:NIO 非阻塞网络通信核心 (Selector 监听)
Selector selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.bind(new InetSocketAddress(8080));
ssc.configureBlocking(false); // 非阻塞模式
ssc.register(selector, SelectionKey.OP_ACCEPT); // 注册ACCEPT事件
while (true) {
if (selector.select() > 0) { // 阻塞直到有事件就绪
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
iter.remove();
if (key.isAcceptable()) { // 处理新连接
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ); // 监听新连接的读
} else if (key.isReadable()) { // 处理可读
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ...;
int read = client.read(buffer); // 非阻塞读取
if (read > 0) { ... } // 处理数据
else if (read == -1) { client.close(); } // 关闭连接
}
}
}
}
三、技术选型建议
- BIO: 简单客户端工具、低并发管理端。
- NIO: 高并发网络服务端开发的核心选择(Netty、Tomcat NIO Connector 底层)。
- NIO.2 (Files/Path): 所有文件操作的首选,简洁安全。
- NIO.2 (Asynchronous*Channel): 超大规模文件 I/O 或特定高性能异步网络场景(需评估复杂性)。
关键洞见: NIO 的核心价值在于 Selector + 非阻塞 Channel 实现的多路复用,突破 BIO 的线程瓶颈。Buffer 是高效数据操作的基石。NIO.2 的文件 API 则大幅提升了开发体验和安全性。
掌握 Java I/O 的多层抽象与演进,是构建高性能、高可伸缩性应用的基石。理解机制差异,方能精准选型,优化资源!
Java I/O:从BIO到NIO.2深度剖析
995

被折叠的 条评论
为什么被折叠?



