NIO能通过单个线程管理多个I/O通道,主要就是通过选择器Selector来实现的

public abstract class Selector {protected Selector() { }public static Selector open() throws IOException {return SelectorProvider.provider().openSelector();}public abstract boolean isOpen();public abstract SelectorProvider provider();public abstract Set<SelectionKey> keys();public abstract Set<SelectionKey> selectedKeys();public abstract int selectNow() throws IOException;public abstract int select(long timeout)throws IOException;public abstract int select() throws IOException;public abstract Selector wakeup();public abstract void close() throws IOException;
}

当我们调用

channel.register(selector, SelectionKey.OP_READ, buffer);

方法时,会将通道channel注册到选择器selector上,同时会返回一个SelectionKey选择键对象,这个键对象标识了通道和选择器之间的注册关系。选择键会记住您关心的通道。它们也会追踪对应的通道是否已经就绪。当您调用一个选择器对象的select( )方法时,相关的键建会被更新,用来检查所有被注册到该选择器的通道。您可以获取一个就绪键的集合,从而找到当时已经就绪的通道。通过遍历这些键,您可以选择出每个从上次您调用select( )开始直到现在,已经就绪的通道。

public abstract class SelectionKey {//以下四个常量是定义的通道的四种操作public static final int OP_READ = 1;public static final int OP_WRITE = 4;public static final int OP_CONNECT = 8;public static final int OP_ACCEPT = 16;//可以针对指定的通道附加一个对象 private volatile Object attachment = null;// 获得通道对象public abstract SelectableChannel channel();// 获得通道所注册的选择器public abstract Selector selector();// 验证通道和选择器之间的注册关系是否还生效public abstract boolean isValid();//将通道放入选择器的已注销集合中public abstract void cancel();//获得该通道所感兴趣的操作public abstract int interestOps();//设置通道感兴趣的操作public abstract SelectionKey interestOps(int paramInt);//获得通道已准备好的操作public abstract int readyOps();public final boolean isReadable() {return ((readyOps() & 0x1) != 0);}public final boolean isWritable() {return ((readyOps() & 0x4) != 0);}public final boolean isConnectable() {return ((readyOps() & 0x8) != 0);}public final boolean isAcceptable() {return ((readyOps() & 0x10) != 0);}public final Object attach(Object paramObject) {Object localObject = this.attachment;this.attachment = paramObject;return localObject;}public final Object attachment() {return this.attachment;}
}

一个SelectionKey选择键对象包含两个以整数形式进行编码的比特掩码一个用于指示那些通道/选择器组合体所关心的操作(instrest集合), 另一个表示通道准备好要执行的操作(ready集合)。可以通过调用键对象的interestOps( )方法来获取,这个interset集合永远不会被选择器改变, 但可以通过调用选择键interestOps(int value )方法并传入一个新的比特掩码参数来改变它。ready集合是interest集合的子集,可以通过调用键的readyOps( )方法来获取相关的通道的已经就绪的操作并且表示了interest集合中从上次调用select( )以来已经就绪的那些操作。

每个选择器selector中会包含三种键的集合,也可以认为是三种状态通道的集合,比较通道和选择键是一一对应的:

  • (1) 注册键的集合,通过register函数进行注册的通道这个集合可以通过Keys()方法返回
  • (2) 已选择键的集合,这个是注册键集合的子集,可以通过selectedKeys()方法返回,该集合中的通道都是准备好执行相应操作的通道
  • (3) 已取消键的集合,这个集合包含了cancel()方法被调用过的键(这个键已经被无效化),但它们还没有被注销。这个集合是选择器对象的私有成员,因而无法直接访问。

当我们调用选择器的select()方法时,会影响上述三种键的集合,调用之后会发生如下过程:

  • 1.已取消的键的集合将会被检查。如果它是非空的,每个已取消的键的集合中的键将从另外两个集合中移除,并且相关的通道将被注销。 这个步骤结束后,已取消的键的集合将是空的。

  • 2.已注册的键的集合中的键的interest集合将被检查。在这个步骤中的检查执行过后,对interest集合的改动不会影响剩余的检查过程。一旦就绪条件被定下来,底层操作系统将会进行查询,以确定每个通道所关心的操作的真实就绪状态。依赖于特定的select( )方法调用,如果没有通道已经准备好,线程可能会在这时阻塞,通常会有一个超时值。直到系统调用完成为止,这个过程可能会使得调用线程睡眠一段时间,然后当前每个通道的就绪状态将确定下来。对于那些还没准备好的通道将不会执行任何的操作。对于那些操作系统指示至少已经准备好interest集合中的一种操作的通道,将执行以下两种操作中的一种:

a.如果通道的键还没有处于已选择的键的集合中,那么键的ready集合将被清空,然后表示操作系统发现的当前通道已经准备好的操作的比特掩码将被设置。
b.否则,也就是键在已选择的键的集合中。键的ready集合将被表示操作系统发现的当前已经准备好的操作的比特掩码更新。所有之前的已经不再是就绪状态的操作不会被清除。事实上,所有的比特位都不会被清理。由操作系统决定的ready集合是与之前的ready集合按位分离的,一旦键被放置于选择器的已选择的键的集合中,它的ready集合将是累积的。比特位只会被设置,不会被清理。

  • 3.步骤2可能会花费很长时间,特别是所激发的线程处于休眠状态时。与该选择器相关的键可能会同时被取消。当步骤2结束时,步骤1将重新执行,以完成任意一个在选择进行的过程中,键已经被取消的通道的注销。

  • 4.select操作返回的值是ready集合在步骤2中被修改的键的数量,而不是已选择的键的集合中的通道的总数。返回值不是已准备好的通道的总数,而是从上一个select()调用之后进入就绪状态的通道的数量。之前的调用中就绪的,并且在本次调用中仍然就绪的通道不会被计入,而那些在前一次调用中已经就绪但已经不再处于就绪状态的通道也不会被计入。这些通道可能仍然在已选择的键的集合中,但不会被计入返回值中。返回值可能是0。

原文链接:https://blog.csdn.net/u011784767/article/details/74750153

Selector SelectionKey相关推荐

  1. Java NIO Selector , SelectionKey , SocketChannel , ServerSocketChannel

    一    NIO介绍 1. NIO是非阻塞的 NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,rea ...

  2. 【Java.NIO】Selector,及SelectionKey

    https://blog.csdn.net/robinjwong/article/details/41792623 java.nio.channels public abstract class Se ...

  3. Java NIO系列教程(六) Selector

    Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管理多个网络连接. 下面是 ...

  4. Java NIO Selector 详解

    Selector 允许一个单一的线程来操作多个 Channel,如果我们的应用程序中使用了多个 Channel,那么使用 Selector 很方便的实现这样的目的,但是因为在一个线程中使用了多个 Ch ...

  5. 【NIO】Selector

    经过前边几节的介绍,我相信大家都掌握了IO多路复用的核心思想了.昨天我给了一个使用C语言进行 linux 编程的IO多路复用的例子.那个例子使用的是 poll 这个系统调用,今天我会给出一个使用Jav ...

  6. java nio Selector (新IO)分析

    Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管理多个网络连接. 为什么 ...

  7. Java NIO之Selector(选择器)

    **Java高级特性增强-NIO 本部分网络上有大量的资源可以参考,在这里做了部分整理并做了部分勘误,感谢前辈的付出,每节文章末尾有引用列表~ 写在所有文字的前面:作者在此特别推荐Google排名第一 ...

  8. Java NIO 学习笔记(三)----Selector

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  9. 【Netty】NIO 网络通信 SelectionKey 常用 API 简介

    文章目录 I . SelectionKey 简介 II . SelectionKey 事件简介 III . SelectionKey 常用 API 简介 I . SelectionKey 简介 1 . ...

最新文章

  1. 视觉SLAM学习--RGB-D SLAM学习(待完善)
  2. java 读取oracle的blob/clob
  3. Android开发学习---使用Intelij idea 13.1 进行android 开发
  4. 在 .NET Core 应用中使用 NHibernate
  5. 说说json和jsonp 也许你会明白它的原理 含有jQuery实例 蛋疼 ,我面试的时候被卡了 赶紧写一个回顾...
  6. 如何处理Win10电脑黑屏后出现代码0xc0000225的错误?
  7. Excel函数公式大全—IF家族函数
  8. latex linux 安装教程,Deepin安装LaTex,
  9. 测试苹果授权登录Sign in with apple时,提示“未完成注册”处理经验分享
  10. 基于Android汽车违章查询app系统
  11. Maven中创建同名项目:Failed to create a Maven project解决(IntelliJ IDEA)
  12. 裁员潮下的打工人,怎么把手里的饭碗端稳?
  13. 孙鑫《VC++深入详解》完整版PDF 下载
  14. 鲲鹏Arm64 openEuler 虚拟机学习
  15. LeetCode/LintCode 题解丨一周爆刷字符串:简化路径
  16. 数商云B2B商城系统订货功能为新能源汽车行业赋能,打造高质量发展生态圈
  17. 【JavaScript】用循环语句解决鸡兔同笼和百元买百鸡问题
  18. 解决Flash Player过期的问题——谷歌浏览器Chrome 87.0.4270.0绿色免安装增强版
  19. antd 下拉框怎么联动_antd下拉框联动使用步骤详解
  20. 如何在win7下装win8以及我的win8之旅

热门文章

  1. Python:每日一题001
  2. 从技术角度讨论微服务
  3. 有关Java中json字符串与map的转换使用
  4. 在这里的周末休息也就是看看奥运
  5. 修改git commit默认触发的编辑器
  6. 由 Session 和 Cookie 的区别说起
  7. 挖一挖C#中那些我们不常用的东西之系列(3)——StackTrace,Trim
  8. Android 创建与解析XML(一)—— 概述
  9. 正确使用 SharePoint 对象避免内存泄漏(续)
  10. Django入门:(admin.E108