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 详解

相关推荐
Goboy10 小时前
【Python修仙笔记.3】Python函数作为秘技 - 封装你的仙法
后端·python
Goboy10 小时前
【Python修仙笔记.4】数据结构法宝 - 存储你的仙器
后端·python
间彧10 小时前
Spring Boot自动配置与"约定大于配置"机制详解
后端
IT_陈寒11 小时前
JavaScript引擎优化:5个90%开发者都不知道的V8隐藏性能技巧
前端·人工智能·后端
JaguarJack11 小时前
PHP "真异步" TrueAsync SAPI 与 NGINX Unit 集成
后端·php
hweiyu0011 小时前
Spring Boot 项目集成 Gradle:构建、测试、打包全流程教程
java·spring boot·后端·gradle
一勺菠萝丶11 小时前
Spring Boot 项目启动报错:`Could not resolve type id ... no such class found` 终极解决方案!
java·spring boot·后端
canonical_entropy11 小时前
组合为什么优于继承:从工程实践到数学本质
后端·数学·设计模式
Victor35611 小时前
Redis(62)如何优化Redis的连接数?
后端
绝无仅有11 小时前
面试真实经历某商银行大厂Java问题和答案总结(三)
后端·面试·github