Selector中的channel注册需要由SelectabelChannel调用其register()方法开始注册流程。具体的register()方法实现在了AbstractSelectableChannel中。

public final SelectionKey register(Selector sel, int ops,Object att)throws ClosedChannelException
{synchronized (regLock) {if (!isOpen())throw new ClosedChannelException();if ((ops & ~validOps()) != 0)throw new IllegalArgumentException();if (blocking)throw new IllegalBlockingModeException();SelectionKey k = findKey(sel);if (k != null) {k.interestOps(ops);k.attach(att);}if (k == null) {// New registrationsynchronized (keyLock) {if (!isOpen())throw new ClosedChannelException();k = ((AbstractSelector)sel).register(this, ops, att);addKey(k);}}return k;}
}

在channel中,将会有一个数组来保存已经注册过了的SelectionKey。一个SelectionKey代表一个channel和一个selector的注册关系。在注册的首先,会通过findKey()来寻找key判断这个channel是否已经注册过。如果这个channel是第一次进行注册操作,那么显然这里是找不到的。具体的findKey()方法实现如下。

private SelectionKey findKey(Selector sel) {synchronized (keyLock) {if (keys == null)return null;for (int i = 0; i < keys.length; i++)if ((keys[i] != null) && (keys[i].selector() == sel))return keys[i];return null;}
}

如果一开始就找到了相应的key,说明该channel与传递进来需要注册的selctor已经注册过,那么就是对相应的interestOps和attach进行更新,并没有新的注册操作。

但是,如果没有找到相应的SelectionKey,就说明需要与传递进来的Selector进行注册操作。

Selector的register()方法实现在了SelectorImpl中。

protected final SelectionKey register(AbstractSelectableChannel var1, int var2, Object var3) {if(!(var1 instanceof SelChImpl)) {throw new IllegalSelectorException();} else {SelectionKeyImpl var4 = new SelectionKeyImpl((SelChImpl)var1, this);var4.attach(var3);Set var5 = this.publicKeys;synchronized(this.publicKeys) {this.implRegister(var4);}var4.interestOps(var2);return var4;}
}

首先,就会根据channel与selector生成相应的SelectionKeyImpl,其构造方法就是简单的保存了传递进来的参数,并且将所需要attach的object进行保存。之后,调用子类的implRegister()方法,以windowsSelectorImpl为例子。

protected void implRegister(SelectionKeyImpl var1) {Object var2 = this.closeLock;synchronized(this.closeLock) {if(this.pollWrapper == null) {throw new ClosedSelectorException();} else {this.growIfNeeded();this.channelArray[this.totalChannels] = var1;var1.setIndex(this.totalChannels);this.fdMap.put(var1);this.keys.add(var1);this.pollWrapper.addEntry(this.totalChannels, var1);++this.totalChannels;}}
}

在这里,便是对SelectionKeyImpl进行进一步的加工,已完成其对注册关系抽象的功能。

此处,由于需要存放新注册的SelectionKey,所以需要对原本存放相应对象的数组长度进行必要的检验,在growIfNeeded()方法中,如果此时数组的长度已经不够,则需要对该数组进行扩容。

private void growIfNeeded() {if(this.channelArray.length == this.totalChannels) {int var1 = this.totalChannels * 2;SelectionKeyImpl[] var2 = new SelectionKeyImpl[var1];System.arraycopy(this.channelArray, 1, var2, 1, this.totalChannels - 1);this.channelArray = var2;this.pollWrapper.grow(var1);}if(this.totalChannels % 1024 == 0) {this.pollWrapper.addWakeupSocket(this.wakeupSourceFd, this.totalChannels);++this.totalChannels;++this.threadsCount;}}

之后,根据当前的channel数量将相应点的channel存放在数组相应的下标下的位置,并在SelectionKey中保存在被注册的selector中的位置索引。之后将在put()方法中完成所注册的channel的FDVal与具体的SelectionKey的键值对的映射。

private WindowsSelectorImpl.MapEntry put(SelectionKeyImpl var1) {return (WindowsSelectorImpl.MapEntry)this.put(new Integer(var1.channel.getFDVal()), new WindowsSelectorImpl.MapEntry(var1));
}

最后,将该SelectionKey与当时的channel数量作为键值对保存在pollWrapper中,最后自增channel数。

当SelectionKey经过Selector的产生后边,将会返回给channel,这个时候通过addKey()将刚刚产生的key添加到channel中。

private void addKey(SelectionKey k) {assert Thread.holdsLock(keyLock);int i = 0;if ((keys != null) && (keyCount < keys.length)) {// Find empty element of key arrayfor (i = 0; i < keys.length; i++)if (keys[i] == null)break;} else if (keys == null) {keys =  new SelectionKey[3];} else {// Grow key arrayint n = keys.length * 2;SelectionKey[] ks =  new SelectionKey[n];for (i = 0; i < keys.length; i++)ks[i] = keys[i];keys = ks;i = keyCount;}keys[i] = k;keyCount++;
}

在addKey()方法中,如果此时大小还足够,那么可以直接在相应的位置顺序将SelectionKey保存,如果需要扩容,则会在扩容之后保存相应的SelectionKey。

jdk的selector(2)channel的注册相关推荐

  1. java selector 源码_Java NIO核心组件-Selector和Channel

    昨天我们介绍了一下SelectorProvider和IO multiplexing.特别是IO multiplexing中的epoll系统调用,是Linux版本的Java的NIO的核心实现. 那今天我 ...

  2. IO到NIO的前因后果,以及NIO的用法(2)——Selector、Channel

    Selector Selector 一般称 为选择器 ,当然你也可以翻译为 多路复用器 .它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读.可写 ...

  3. 【Netty】NIO 选择器 ( Selector ) 通道 ( Channel ) 缓冲区 ( Buffer ) 网络通信案例

    文章目录 I . NIO 通信 服务器端 流程说明 II . NIO 通信 服务器端代码 III . NIO 通信 客户端 流程说明 IV . NIO 通信 客户端代码 V . NIO 通信 示例运行 ...

  4. NIO : selector、channel、buffer的实例

    不同的SelectableChannel所支持的操作是不同的.例如ServerSocketChannel代表一个ServerSocket,它就只支持OP_ACCEPT操作: 当Selector上注册的 ...

  5. jdk的Selector(3)select的过程

    当调用了SelectorImpl的select()方法的时候,同时会将所带的参数,也就是给select()所设置的timeout,之后会调用lockAndDoSelect(),在这个方法中,主要还是调 ...

  6. 【Netty】NIO 简介 ( NIO 模型 | NIO 三大组件 | 选择器 Selector | 通道 Channel | 缓冲区 Buffer | NIO 组件分配 | 缓冲区示例 )

    文章目录 I . NIO 模型 II . NIO 三大组件交互流程 III . NIO 缓冲区 IV . NIO 与 BIO 对比 V . NIO 线程分配 VI . 缓冲区 ( Buffer ) 示 ...

  7. jdk的selector(1)

    在java中如过需要用到Selector来处理Nio的情况下,需要先使用SelectorProvider的provider()方法来取得相应的SelectorProvider. public stat ...

  8. Java NIO SocketChannel+Buffer+Selector 详解(含多人聊天室实例)

    一.Java NIO 的核心组件 Java NIO的核心组件包括:Channel(通道),Buffer(缓冲区),Selector(选择器),其中Channel和Buffer比较好理解  简单来说 N ...

  9. ktor框架用到了netty吗_Netty系列相关面试题汇总

    Netty是一个高性能的框架,使用的地方非常多,面试题也经常提问.本套题来源比较多,最主要的来源是ThinkWon,地址是https://thinkwon.blog.csdn.net/article/ ...

最新文章

  1. ajax的auto是true,一个AJAX自动完成功能的js封装源码[支持中文]
  2. SQL Server:APPLY表运算符
  3. 组织可以最大限度提高数据中心性能的五个步骤
  4. 逻辑回归和线性回归的区别_机器学习简介之基础理论- 线性回归、逻辑回归、神经网络...
  5. 每日程序C语言30-static作用
  6. 用jQuery监听浏览器窗口的变化
  7. Java并发编程实战~Lock
  8. C#开发ActiveX控件及制作CAB包
  9. MateBook14一个多月的使用体验(开发向)
  10. vos2009 校验版本超时_开源多云应用平台 Choerodon猪齿鱼发布0.14版本
  11. 一文带你了解Java编程语言的前世今生 | Java核心知识点整理
  12. 二级C语言考前学习资料(机试)及C语言程序二十四种大题题型
  13. 微信小程序——mock.js模拟后台交互
  14. VS2003下载地址
  15. 各大EMM厂商功能比较 第三部分 Network Gateway比较
  16. mysql字段最大长度_MySQL VARCHAR字段最大长度到底是多少
  17. 你三十岁的生日,我写文章纪念 (西祠旧贴)
  18. SCIPY类库——最小二乘法应用
  19. 计算机主机版bga球径,BGA
  20. 一键生成舞曲编排的小程序(perl)

热门文章

  1. 诗与远方:无题(十四)
  2. VMware客户端vSphereClient新建虚拟机
  3. MySQL启用SSL连接
  4. Avoided redundant navigation to current location
  5. SpringBoot使用RequestBodyAdvice进行统一参数处理
  6. [蓝桥杯][2019年第十届真题c/c++B组]迷宫(寻找路径bfs及文件输入输出)
  7. STL(五)——slist/list链表
  8. python3.6安装pip3_python3安装pip3的实例步骤
  9. bootstrap bootstraptable 固定列_BootStrapTable分页
  10. Zeppelin 可视化操作spark sql