全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-10 9 分钟 ✍️ juanwangdev

NIO 非阻塞模式

非阻塞 IO 是 NIO 的核心特性,通过 Selector 实现高效的多连接管理。

阻塞 vs 非阻塞

特性阻塞 IO非阻塞 NIO
等待数据等待直到数据就绪立即返回,未就绪返回 0
线程模型一个连接一个线程单线程管理多连接
资源消耗线程多,消耗大线程少,消耗小
适用场景低并发高并发

非阻塞模式设置

Java
// Channel 设置为非阻塞
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);  // 关键:设为非阻塞

ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);  // 服务端通道非阻塞

必须设置非阻塞:默认是阻塞模式,必须调用 configureBlocking(false)。

Selector 工作流程

1. 创建 Selector

Java
Selector selector = Selector.open();

2. 注册 Channel

Java
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);  // 非阻塞
serverChannel.register(selector, SelectionKey.OP_ACCEPT);

3. 事件循环

Java
while (true) {
    // 等待至少一个事件发生
    int readyCount = selector.select();  // 阻塞等待
    // int readyCount = selector.selectNow();  // 立即返回

    if (readyCount == 0) continue;

    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    Iterator<SelectionKey> iter = selectedKeys.iterator();

    while (iter.hasNext()) {
        SelectionKey key = iter.next();
        iter.remove();  // 移除已处理的 key

        if (key.isAcceptable()) {
            handleAccept(key);
        }
        if (key.isReadable()) {
            handleRead(key);
        }
        if (key.isWritable()) {
            handleWrite(key);
        }
    }
}

4. 处理事件

Java
private void handleAccept(SelectionKey key) throws IOException {
    ServerSocketChannel server = (ServerSocketChannel) key.channel();
    SocketChannel client = server.accept();  // 接收连接
    client.configureBlocking(false);
    client.register(key.selector(), SelectionKey.OP_READ);
}

private void handleRead(SelectionKey key) throws IOException {
    SocketChannel client = (SocketChannel) key.channel();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    int len = client.read(buffer);  // 非阻塞,未就绪返回 0

    if (len == -1) {
        client.close();  // 连接关闭
    } else if (len > 0) {
        buffer.flip();
        // 处理数据
    }
}

select() 方法区别

方法行为
select()阻塞直到至少一个事件发生
select(timeout)阻塞最多 timeout 毫秒
selectNow()立即返回,不阻塞

必须移除已处理的 key:iterator.remove() 防止重复处理。

完整服务端示例

Java
public class NioServer {
    public static void main(String[] args) throws IOException {
        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();
            for (SelectionKey key : selector.selectedKeys()) {
                selector.selectedKeys().remove(key);

                if (key.isAcceptable()) {
                    SocketChannel client = server.accept();
                    client.configureBlocking(false);
                    client.register(selector, SelectionKey.OP_READ);
                }
                if (key.isReadable()) {
                    SocketChannel client = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    if (client.read(buffer) == -1) {
                        client.close();
                    }
                }
            }
        }
    }
}

要点总结

  • 非阻塞模式:configureBlocking(false)
  • Selector 监控多个 Channel 事件
  • select() 阻塞等待事件,selectNow() 立即返回
  • 处理完 SelectionKey 必须移除,避免重复处理
  • 单线程管理多连接,适合高并发网络场景
  • 非阻塞读返回 0 表示数据未就绪,返回 -1 表示连接关闭

📝 发现内容有误?点击此处直接编辑

← 上一篇 NIO 核心组件(Channel、Buffer、Selector)
下一篇 → Path、Files 与 FileSystem API
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库