温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

java nio选择器怎么用

发布时间:2026-10-13 14:29:25 来源:亿速云 阅读:95 作者:小樊 栏目:编程语言

Java NIO 中的 Selector(选择器) 用于实现 多路复用 IO,可以用一个线程管理多个 Channel(如 SocketChannel、ServerSocketChannel),非常适合写高性能网络服务器。

下面从 概念 → 使用步骤 → 完整示例 给你讲清楚。


一、Selector 核心概念

1. 什么是 Selector

  • Selector 可以 监听多个 Channel 的事件
  • 常见事件:
    • OP_ACCEPT:服务端接收连接
    • OP_CONNECT:客户端连接完成
    • OP_READ:可读
    • OP_WRITE:可写

2. 前提条件

  • Channel 必须是 非阻塞模式
channel.configureBlocking(false);

二、Selector 使用步骤

步骤 1:创建 Selector

Selector selector = Selector.open();

步骤 2:创建 Channel 并注册

ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);

serverChannel.register(selector, SelectionKey.OP_ACCEPT);

步骤 3:事件循环(核心)

while (true) {
    int readyChannels = selector.select(); // 阻塞等待事件
    if (readyChannels == 0) continue;

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

    while (it.hasNext()) {
        SelectionKey key = it.next();
        it.remove(); // 必须移除

        if (key.isAcceptable()) {
            // 有连接进来
        }
        if (key.isReadable()) {
            // 有数据可读
        }
    }
}

三、完整示例(TCP 服务端)

public class NioServer {
    public static void main(String[] args) throws Exception {
        Selector selector = Selector.open();

        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.bind(new InetSocketAddress(8080));
        serverChannel.configureBlocking(false);
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("Server started...");

        while (true) {
            selector.select();
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();

            while (it.hasNext()) {
                SelectionKey key = it.next();
                it.remove();

                if (key.isAcceptable()) {
                    ServerSocketChannel server =
                            (ServerSocketChannel) key.channel();
                    SocketChannel client = server.accept();
                    client.configureBlocking(false);
                    client.register(selector, SelectionKey.OP_READ);
                    System.out.println("Client connected");

                } else if (key.isReadable()) {
                    SocketChannel client = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int len = client.read(buffer);

                    if (len > 0) {
                        buffer.flip();
                        System.out.println("Received: " +
                                new String(buffer.array(), 0, len));
                        client.write(buffer);
                    } else if (len == -1) {
                        client.close();
                    }
                }
            }
        }
    }
}

四、客户端简单示例

SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("localhost", 8080));

Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_CONNECT);

五、常见坑点 ⚠️

  1. 必须 it.remove()
  2. Channel 必须非阻塞
  3. select() 会阻塞,selectNow() 不阻塞
  4. 写事件(OP_WRITE)一般不要一直注册,避免 CPU 空转
  5. 注册事件可用位运算:
channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);

六、什么时候用 Selector?

✅ 高并发网络服务
✅ 单线程处理大量连接
❌ 简单程序、少量连接(用 BIO 更简单)


如果你愿意,我可以:

  • 给你 Netty 对比版
  • 讲 Epoll / 多 Reactor 模型
  • 帮你改一份你现有的 NIO 代码

你想看哪个?

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI
助
手