Skip to content
清晨的一缕阳光
返回

Java IO 演进之路

Java IO 演进之路

Java IO 从基于流的阻塞 IO 演进到基于缓冲区的非阻塞 IO,是高并发网络编程的基础。

一、整体架构

Java IO 演进
├── BIO (Blocking IO) - JDK 1.0
│   └── 基于流,阻塞式
├── NIO (New IO) - JDK 1.4
│   └── 基于缓冲区,非阻塞 + 多路复用
└── NIO.2 (AIO) - JDK 7
    └── 异步 IO

二、BIO(阻塞 IO)

2.1 核心特点

特点说明
面向流数据按顺序读写
阻塞式read/write 时线程等待
单向传输输入流/输出流分离

2.2 体系结构

IO 流
├── 字节流
│   ├── InputStream(输入)
│   └── OutputStream(输出)
└── 字符流
    ├── Reader(输入)
    └── Writer(输出)

2.3 使用示例

// 文件读取
try (InputStream in = new FileInputStream("data.txt");
     BufferedInputStream bis = new BufferedInputStream(in)) {
    
    byte[] buffer = new byte[1024];
    int len;
    while ((len = bis.read(buffer)) != -1) {
        // 阻塞式读取
        System.out.println(new String(buffer, 0, len));
    }
}

2.4 缺点


三、NIO(非阻塞 IO)

3.1 核心组件

NIO 三剑客
├── Buffer(缓冲区) - 数据容器
├── Channel(通道) - 双向传输
└── Selector(选择器) - 多路复用

3.2 Buffer(缓冲区)

核心属性

ByteBuffer buffer = ByteBuffer.allocate(1024);
// capacity: 总容量(固定)
// position: 当前位置
// limit: 读写边界

常用方法

buffer.put(data);    // 写入
buffer.flip();       // 切换读写模式
buffer.get();        // 读取
buffer.clear();      // 清空

3.3 Channel(通道)

特点

常用实现

FileChannel          // 文件读写
SocketChannel        // TCP 客户端
ServerSocketChannel  // TCP 服务端
DatagramChannel      // UDP

3.4 Selector(选择器)

核心作用:单线程管理多个通道的可读/可写事件

工作流程

// 1. 创建 Selector
Selector selector = Selector.open();

// 2. 注册通道(需非阻塞)
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);

// 3. 轮询事件
while (true) {
    selector.select(); // 阻塞等待
    Set<SelectionKey> keys = selector.selectedKeys();
    
    for (SelectionKey key : keys) {
        if (key.isReadable()) {
            // 处理读事件
        }
        if (key.isWritable()) {
            // 处理写事件
        }
    }
    keys.remove();
}

四、BIO vs NIO

对比维度BIONIO
数据模型面向流面向缓冲区
阻塞特性阻塞非阻塞
线程模型一个连接一个线程单线程多连接
适用场景低并发、简单 IO高并发网络

五、NIO 实战

5.1 NIO 服务器

public class NioServer {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel server = ServerSocketChannel.open();
        server.bind(new InetSocketAddress(8080));
        server.configureBlocking(false);
        
        Selector selector = Selector.open();
        server.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 = server.accept();
                    client.configureBlocking(false);
                    client.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    SocketChannel client = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int len = client.read(buffer);
                    if (len > 0) {
                        buffer.flip();
                        client.write(buffer);
                    }
                }
            }
        }
    }
}

5.2 零拷贝

传统 IO

磁盘 → 内核缓冲区 → 用户缓冲区 → Socket 缓冲区 → 网络
        (4 次拷贝,4 次上下文切换)

NIO 零拷贝

磁盘 → 内核缓冲区 → Socket 缓冲区 → 网络
        (sendfile,2 次拷贝,2 次上下文切换)

实现

FileChannel fileChannel = new FileInputStream("file.txt").getChannel();
SocketChannel socketChannel = SocketChannel.open();

// 零拷贝传输
fileChannel.transferTo(0, fileChannel.size(), socketChannel);

六、总结

Java IO 核心要点:

特性BIONIO
核心流(Stream)缓冲区(Buffer)
阻塞
多路复用是(Selector)
适用简单 IO高并发网络

NIO 是 Netty 等高性能框架的基础,理解 NIO 对掌握高并发编程至关重要。


分享这篇文章到:

上一篇文章
JVM 内存模型详解
下一篇文章
Java 线程池实战指南