Java进阶篇之NIO基础
📌 引言
在前面的文章中,我们介绍了序列化和反序列化(Java进阶篇之序列化和反序列化)在 Java 的 I/O 体系中,java.io
提供了传统的BIO(Blocking I/O,阻塞 I/O),它适用于小规模的数据交互。但在高并发、大数据量传输的场景下,java.nio
(New I/O,非阻塞 I/O)提供了更高效的解决方案。NIO 采用**缓冲区(Buffer)+ 通道(Channel)**的方式,提高了数据处理能力,并支持 多路复用(Selector),大大提升了 I/O 性能。
本篇文章将详细介绍 Java NIO 的基础概念、核心组件、使用示例,并对比传统 IO,帮助你更好地理解 NIO 的工作原理。
目录
📌 引言
🏗 一、NIO 概述
1️⃣ 传统 I/O(BIO)的缺点
2️⃣ NIO 的优势
🛠 二、NIO 的核心组件
1️⃣ Buffer(缓冲区)
2️⃣ Channel(通道)
3️⃣ Selector(多路复用器)
🔄 四、NIO vs 传统IO
🎯 结语
🏗 一、NIO 概述
1️⃣ 传统 I/O(BIO)的缺点
- 阻塞模式:BIO 采用 流式处理,读取或写入数据时必须等待操作完成,线程可能被阻塞。
- 线程消耗大:每个连接通常对应一个独立的线程,在高并发场景下,线程资源消耗过多,导致性能下降。
- 数据复制:BIO 需要频繁在用户空间和内核空间之间拷贝数据,影响 I/O 性能。
2️⃣ NIO 的优势
- 非阻塞 I/O:NIO 允许一个线程管理多个连接,无需为每个连接创建线程。
- 基于 Buffer(缓冲区):相比于传统的 Stream(流),NIO 以块(Block)形式处理数据,减少数据拷贝,提高吞吐量。
- 使用 Channel(通道):双向数据通道,可同时进行读写操作,避免了 BIO 的单向流式传输。
- 支持 Selector(多路复用器):一个线程可以管理多个通道,提高资源利用率。
🛠 二、NIO 的核心组件
Java NIO 主要由 Buffer(缓冲区)、Channel(通道)、Selector(选择器) 组成:
1️⃣ Buffer(缓冲区)
缓冲区用于存储数据,NIO 不再直接与流交互,而是通过 Buffer 进行数据的读取和写入。常见的 Buffer 类型:
Buffer 类型 | 作用 |
---|---|
ByteBuffer | 处理字节数据 |
CharBuffer | 处理字符数据 |
IntBuffer | 处理整数数据 |
FloatBuffer | 处理浮点数数据 |
LongBuffer | 处理长整数数据 |
DoubleBuffer | 处理双精度浮点数数据 |
Buffer 关键方法:
allocate(int capacity)
:创建指定容量的 Buffer。put(data)
:向 Buffer 写入数据。flip()
:切换为读模式。get()
:从 Buffer 读取数据。clear()
:清空 Buffer,准备下一次写入。
示例:使用 ByteBuffer
存储数据
import java.nio.ByteBuffer;
public class BufferExample {
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(10); // 创建容量为 10 的缓冲区
// 写入数据
buffer.put((byte) 1);
buffer.put((byte) 2);
buffer.put((byte) 3);
buffer.flip(); // 切换到读模式
while (buffer.hasRemaining()) {
System.out.println(buffer.get()); // 读取数据
}
}
}
2️⃣ Channel(通道)
通道类似于传统的流(Stream),但它支持双向数据传输(既可读,也可写)。
常见的 Channel
实现:
FileChannel
:用于文件读写。SocketChannel
:用于网络通信(类似Socket
)。ServerSocketChannel
:用于服务器端的Socket
监听。DatagramChannel
:用于 UDP 连接。
示例:使用 FileChannel
读取文件
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class FileChannelExample {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("test.txt");
FileChannel channel = fis.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
buffer.flip(); // 切换到读模式
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
channel.close();
fis.close();
}
}
3️⃣ Selector(多路复用器)
Selector 允许 单个线程管理多个通道,提高了 I/O 处理效率,特别适用于高并发场景,如 Web 服务器、聊天室等。
Selector 关键方法
select()
:阻塞直到至少一个通道准备就绪。selectNow()
:非阻塞检查就绪通道。register()
:将Channel
注册到Selector
上。
示例:使用 Selector
监听多个 Channel
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.net.InetSocketAddress;
import java.util.Iterator;
public class SelectorExample {
public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // 阻塞等待事件
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()) { // 处理新连接
SocketChannel client = serverChannel.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
System.out.println("Client connected: " + client.getRemoteAddress());
} else if (key.isReadable()) { // 读取数据
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = client.read(buffer);
if (bytesRead > 0) {
buffer.flip();
System.out.println("Received: " + new String(buffer.array(), 0, bytesRead));
}
}
}
}
}
}
🔄 四、NIO vs 传统IO
对比项 | 传统 I/O (BIO) | NIO (非阻塞 I/O) |
---|---|---|
数据处理 | 基于流 | 基于缓冲区(Buffer) |
阻塞模式 | 阻塞(每次读写都等待完成) | 非阻塞(一个线程可管理多个连接) |
适用场景 | 小数据量、单连接 | 高并发、大量连接 |
线程模型 | 每连接一个线程 | 单线程管理多个连接 |
🎯 结语
Java NIO 是高性能 I/O 编程的基础,适用于高并发、低延迟的应用场景。本文介绍了 NIO 的基本概念、核心组件(Buffer、Channel、Selector)及代码示例,希望能帮助你更好地理解 NIO 的应用。
下一步,你可以尝试使用NIO实现简单的 Web 服务器或聊天室,进一步加深对非阻塞 I/O 的理解!💡
在接下来的文章中,我们将继续探讨Java中的多线程以及其他重要特性,敬请期待!
👉 如果你觉得这篇文章对你有所帮助,欢迎点赞、收藏、分享!😊