NIO 向Selector注册Channel
执行ServerSocketChannelImpl.register(),入参为selector(这里是WindowsSelectorImpl)和selector需要关注的事件,这里是SelectionKey.OP_ACCEPT,其实就是一个数字
先执行SelectableChannel的register
再执行AbstractSelectableChannel的register
AbstractSelectableChannel # register()
这里有四步是关键,第1步获取key,2、 3 是 key不为null时的处理逻辑,4是key 为null时的处理逻辑
向Selector注册Channel,我们可以把Selector理解为一个快递分发中心,而所有的Channel都可以理解为快递小哥,首先所有的快递小哥要在分发中心注册,注册之后返回一个唯一的key作为身份标识,之后当属于该快递小哥运送区域的快递到来时Selector就会去通知该快递小哥。(这样就可以理解key为null代表该Channel还没有注册到Selector,需要执行第4步进行注册)
(1)key为null时
4. k = ((AbstractSelector)sel).register(this, ops, att);注册key
先来看入参:
- selector对象
- 操作 operation,是一个int值
- 一个对象,这个对象是做什么的?(下文解释)
这时候就需要SelectionKeyImpl组件的参与
分为四步:
- 创建一个SelectionKeyImpl
- 执行attach操作
- 执行注册implRegister
- 执行SelectionKeyImpl.interestOps
先创建一个SelectionKeyImpl,然后执行attach操作
这里用到了原子更新引用类AtomicReferenceFieldUpdater,它的目的是原子更新对象中的一个volatile字段,也就是这里的attachme对象,以这里为例首先通过newUpdater创建一个该对象,入参分别是attachment所在类、attachment类型以及该字段名称,然后通过调用该对象的getAndSet方法原子更新attachment的值,这里的新value是null,所以最终实现的效果是原子更新对象SelectionImpl的volatile字段 attachment的值为null。
执行完attach操作,就该
WindowsSelectorImpl#implRegister
绑定感兴趣的事件,这个也是NIO重要的点之一。
SelectionKeysImpl具有属性,此时设置该属性。
最后一步,addKey(k); 没啥操作,就是在Channel这边创建一个数据结构存放注册给Selector返回的SelectionKeyImpl。