源码阅读:理解反应器模式在javaNIO中的实现-Selector1

源码阅读:理解反应器模式在javaNIO中的实现-Selector

今天来看看Selector源码
又是一长串的注解,太棒了。
第一句:

是提供给Selectablechannel的多路解调器(可不可以理解为分发工具?)
A multiplexor of {@link SelectableChannel} objects.

以下是对类上注解的翻译,接下来就不贴原文了:

selector是通过selectorProvider创建的,其必须通过自身的close()方法才能关闭。
通过selectionKey将selectable channel与seletor绑定。

一个selector维护三个selection键的集合:

key set :存储了当前选择器的channel注册信息,是其余两个set的父集合。

selected-key set: 其存储了监听到至少一个兴趣点(interest)的通道信息。

interest:包括OP_READ、OP_WRITE、OP_CONNECT、OP_ACCEPT,selectionKey可以绑定一个至多个interest。

cancelled-key:是被取消的key的集合,但是其绑定的channel还未被注销。

通过register方法会将key添加到key set中。key set本身是无法被修改的。

当其调用了cancel方法,或者其绑定的channel被关闭时,该key会添加到cancelled-key set中。cancel方法会让key在下一次操作(selection operation)中注销其绑定的channel,并将该key移除key set。

(这边的selection operation指的就是上面的读、写、连接、接收四个OP)

selected-key set里的key只能通过remove方法被移除(包括自身的remove方法以及iterator的remove方法)

关于Selection

selection通过3个方法去获得就绪(能够执行io操作)的个数。
select():

同步获取,如果获取不到,就会一直阻塞。

select(long)
同步获取,但是会设置超时时间。

selectNow()
非阻塞的获取。

这三个方法都会包含3个步骤:

1.

把所有已注销的channel所绑定的key从cancelled-key set中移除。

2.

更新获取对channel所绑定的感兴趣事件就绪的channel,针对这类channel,执行以下两步:

2.1:

如果该channel对应的key还不在selected-key set中,添加进去,并更新ready-operation set中channel所就绪的operations,并清除之前所有的就绪信息(正在情况下之前应该也是没有就绪信息的)。

2.2:

如果已经在selected-key中了,则更新ready-operation set中channel所就绪的operations,并保留之前的就绪信息。(ready operations就是已经就绪的操作(上面所述那4种))

3:

如果key set中任何一个key都没有感兴趣事件,那么步骤不会往下走。

如果在执行第二步时有canceled-key set被添加了,则这些被添加的keys会先执行第一步操作。(即判断这些是否已注销,若已注销,移除之)

总结:在获得selectedKey之前,需要先调用select()方法更新selectedKey信息,获得channel更新的就绪信息。
select()方法会更新selectedKey set,也会从cancelled-key中移除已注销的channel。

关于并发

seletors本身是支持并发线程的,但是其key set不支持。
在执行上述(1) 和(3)时需要对cancelled-key set加上sync方法体。
如果在执行selection operations时更新了channel的感兴趣就绪事件,会等这次执行结束才更新。

自己理解:比如在read时发现可以write了,其write的后续操作handler也要在read结束之后。

可以知道上面的select()方法可能会导致堵塞,有以下三种方式中断:

1.调用wakeup方法。
2.调用close方法。
3.调用当前线程的interrupt方法。

close()方法会给阻塞seletor及其3个set。

好了,接下来看下面的方法:


public abstract class Selector implements Closeable {

    //初始化
    protected Selector() { }

    //由SelectorProvider开启
    public static Selector open() throws IOException {
        return SelectorProvider.provider().openSelector();
    }

    /判断是否开启
    public abstract boolean isOpen();

    //获得创建selecotr的provider,这个类在下一篇文章来读
    public abstract SelectorProvider provider();

    //返回keyset,下面的几个方法都在上文有所描述,不再写
    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;

}

总结:
selector将channel与选择器进行绑定,并可以通过select()方法轮询channel的感兴趣事件的就绪状态,并获得selectedKey set(其中就是就绪的keys),通过拿到key可以进行后续操作。

下篇文章来要研究key所属类SelectionKey的组成,以及其provider类SelectorProvider。

发布了7 篇原创文章 · 获赞 0 · 访问量 453
App 阅读领勋章
微信扫码 下载APP
阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览