NIO SelectionKey 详解

SelectionKey 是 Java NIO 中的一个重要类,用于表示一个通道在 Selector 上的注册关系。它包含了通道的状态信息和感兴趣的事件类型。SelectionKey 是使用 Selector 时的核心组件之一,因为它帮助管理和识别通道的 I/O事件。

SelectionKey 的基本概念

  • 通道(Channel) :代表一个可以进行 I/O 操作的实体,如 SocketChannelServerSocketChannel 等。
  • 选择器(Selector):用于监视多个通道上的 I/O事件。
  • 选择键(SelectionKey) :表示一个通道在 Selector 上的注册,包含该通道的事件兴趣和状态。

SelectionKey 的常量

SelectionKey 使用了一些常量来表示通道的不同事件类型:

  • OP_READ:表示通道中有数据可读。
  • OP_WRITE:表示通道可以写数据。
  • OP_CONNECT:表示连接操作已经完成。
  • OP_ACCEPT:表示服务器通道已准备好接受新的连接。

这些常量是位掩码,可以组合使用。例如,OP_READ | OP_WRITE 表示对读和写事件都感兴趣。

SelectionKey 的主要方法

  1. interestOps()

    java 复制代码
    int interestSet = selectionKey.interestOps();

    返回当前选择键的兴趣集,即通道感兴趣的操作。

  2. interestOps(int ops)

    java 复制代码
    selectionKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);

    设置通道的兴趣集,指定对哪些操作感兴趣。

  3. readyOps()

    java 复制代码
    int readySet = selectionKey.readyOps();

    返回通道已经准备好的操作集。

  4. channel()

    java 复制代码
    SelectableChannel channel = selectionKey.channel();

    返回与此选择键关联的通道。

  5. selector()

    java 复制代码
    Selector selector = selectionKey.selector();

    返回生成此选择键的选择器。

  6. isValid()

    java 复制代码
    boolean valid = selectionKey.isValid();

    检查选择键是否仍然有效。

  7. cancel()

    java 复制代码
    selectionKey.cancel();

    取消选择键,使其无效。

  8. attach(Object obj)attachment()

    java 复制代码
    selectionKey.attach(someObject);
    Object attached = selectionKey.attachment();

    可以将一个对象附加到选择键上,便于在处理事件时访问相关数据。

使用 SelectionKey

在使用 Selector 进行非阻塞 I/O 操作时,SelectionKey 用于识别哪些通道已经准备好进行 I/O 操作,并获取相关的通道和附加信息。

示例

以下是一个简单的使用 SelectionKey 的示例:

java 复制代码
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();
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

    while (keyIterator.hasNext()) {
        SelectionKey key = keyIterator.next();

        if (key.isAcceptable()) {
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
            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(256);
            client.read(buffer);
            // 处理读取的数据
        }

        keyIterator.remove();
    }
}

注意事项

  • 有效性 :在处理完一个 SelectionKey 后,通常需要调用 keyIterator.remove() 来从集合中移除它,以避免重复处理。
  • 附加对象 :可以通过 attach()attachment() 方法将上下文信息附加到选择键上,方便在事件处理时使用。
  • 取消键 :当通道不再需要时,可以调用 cancel() 方法取消选择键。

SelectionKey 是 Java NIO 中实现高效非阻塞 I/O 操作的关键工具之一,通过它可以有效地管理和处理多个通道的事件。

参考

NIO Selector 详解

相关推荐
想用offer打牌7 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX9 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了9 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法9 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
Moment10 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
Cobyte11 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc
程序员侠客行11 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
Honmaple12 小时前
QMD (Quarto Markdown) 搭建与使用指南
后端
PP东12 小时前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
invicinble12 小时前
springboot的核心实现机制原理
java·spring boot·后端