Java 基础之NIO 学习详解

NIO,全称为“New IO”,是Java 1.4 引入的一套用于更高效的 I/O 操作的API。NIO主要包括以下三个核心组件:Channel、Buffer 和 Selector。其中,Channel 和 Buffer 主要用于底层数据传输,Selector 则用于监听 Channel 上的 IO 事件。

Java 基础之NIO 学习详解

简述

NIO,全称为“New IO”,是Java 1.4 引入的一套用于更高效的 I/O 操作的API。NIO主要包括以下三个核心组件:Channel、Buffer 和 Selector。其中,Channel 和 Buffer 主要用于底层数据传输,Selector 则用于监听 Channel 上的 IO 事件。

NIO 与传统 IO 的区别

在传统 IO 模型中,当一个线程被分配到一个 Socket 后,这个线程就会一直阻塞等待,直到数据到达,而在 NIO 模型中,数据异步地读取到缓冲区,线程可以继续处理其他请求,从而提高了系统的并发处理能力。

NIO 的核心组件

Channel

Channel 可以看作是一个数据源的抽象。例如文件、网络套接字或一个能够实现 I/O 操作的硬件设备都可以通过 Channel 进行数据读写。Channel 与 Stream 的区别就像是将数据源分成了读取与写入两个部分。

Buffer

Buffer 可以看作是一个存储字节的数组。它有一个指针 position 表示下一个读或写的位置,一个 limit 表示结束位置,一个 capacity 表示数组的容量。当Buffer缓冲区中有数据读写时,指针 position 会向前移动。

Selector

Selector 用于监听多个 Channel 上的 I/O 事件。因为在 NIO 中,一个线程可以监听多个 Channel,因此使用 Selector 可以节省线程开销,提高程序的并发性能。

NIO应用

下面我们来看一些 NIO 应用实例。

示例1:NIO读取文件

public static void readFile(String path) throws IOException {
    RandomAccessFile file = new RandomAccessFile(path, "rw");
    FileChannel channel = file.getChannel();

    // 初始化 ByteBuffer
    ByteBuffer buffer = ByteBuffer.allocate(1024);

    int bytesRead = channel.read(buffer);
    while (bytesRead != -1) {
        // 将 ByteBuffer 从写模式变成读模式
        buffer.flip();

        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }

        buffer.clear();
        bytesRead = channel.read(buffer);
    }

    channel.close();
    file.close();
}

示例2:NIO服务器

这是一个基于NIO的简单服务器应用,可以同时处理多个客户端请求。

public static void server() throws IOException {
    // 创建 ServerSocketChannel
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.socket().bind(new InetSocketAddress(8888));
    serverSocketChannel.configureBlocking(false);

    // 创建 Selector
    Selector selector = Selector.open();
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

    while (true) {
        int readyChannelsCount = selector.select();
        if (readyChannelsCount == 0) {
            continue;
        }

        Set<SelectionKey> selectedKeys = selector.selectedKeys();
        Iterator<SelectionKey> iterator = selectedKeys.iterator();
        while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            if (key.isAcceptable()) {
                // 新的客户端连接
                SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
                socketChannel.configureBlocking(false);
                socketChannel.register(selector, SelectionKey.OP_READ);
                System.out.println("New client connected");
            } else if (key.isReadable()) {
                // 读取客户端请求
                SocketChannel socketChannel = (SocketChannel) key.channel();
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                int bytesRead = socketChannel.read(buffer);
                if (bytesRead > 0) {
                    buffer.flip();
                    String request = new String(buffer.array(), 0, bytesRead);
                    System.out.println("Received request: " + request);

                    // 处理请求

                    // 发送响应
                    buffer.clear();
                    String response = "Hello, client";
                    buffer.put(response.getBytes());
                    buffer.flip();
                    socketChannel.write(buffer);
                } else {
                    socketChannel.close();
                    System.out.println("Client disconnected");
                }
            }
            iterator.remove();
        }
    }
}

以上是关于 NIO 的一个简单介绍以及两个示例的详细说明。

本文标题为:Java 基础之NIO 学习详解

基础教程推荐