前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NIO 之 Selector实现原理

NIO 之 Selector实现原理

作者头像
java404
发布2018-05-18 12:13:37
1.3K0
发布2018-05-18 12:13:37
举报
文章被收录于专栏:java 成神之路java 成神之路
相关文章

NIO 之 ByteBuffer实现原理

NIO 之 Channel实现原理

NIO 之 Selector实现原理

概述

Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。

这是在一个单线程中使用一个Selector处理3个Channel的图示:

selector与channel关系

要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。

Selector 作用

仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源(如内存)。因此,使用的线程越少越好。

Selector能够在单个线程中处理多个通道,这样可以减少多个线程造成上下文切换问题。

Selector 源码分析

代码语言:javascript
复制
public abstract class Selector implements Closeable {
    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;

Selector 是个抽象类,提供一个静态的方法获取Selector子类SelectorImpl的实例。

下面分析Selector的几个方法

register 方法

该方法是在 Channel的register方法中调用的。具体详见NIO 之 Channel实现原理

register 方法

  1. 通过channel和selector构造一个SelectionKey的实例。
  2. SelectionKey 注册感兴趣的事件

这四种事件用SelectionKey的四个常量来表示: SelectionKey.OP_CONNECT SelectionKey.OP_ACCEPT SelectionKey.OP_READ SelectionKey.OP_WRITE

select 方法

不同的 Channel 注册到 Selector 后,就可以随时查询 Selector ,找出哪些 Channel 已经准备好可以进行处理。Channel 可能准备好上面注册到 Selector 感兴趣事件中的一个或多个。

  1. select() 获取就绪的 Channel,阻塞方法,没有就绪的 Channel 就一直阻塞该线程。
代码语言:javascript
复制
public int select() throws IOException {
    return select(0);
}
  1. select(long timeout) 获取就绪的 Channel, 阻塞方法,阻塞 timeout 时间,如果超时还没有就绪的 Channel,返回0,不做任何操作。
代码语言:javascript
复制
public int select(long timeout)
        throws IOException
    {
        if (timeout < 0)
            throw new IllegalArgumentException("Negative timeout");
        return lockAndDoSelect((timeout == 0) ? -1 : timeout);
    }
  1. selectNow() 获取就绪的 Channel,如果没有就绪的就直接返回,不阻塞当前线程。
代码语言:javascript
复制
public int selectNow() throws IOException {
        return lockAndDoSelect(0);
    }

上面三个 select方法底层都是调用 lockAndDoSelect 方法。 lockAndDoSelect方法的参数值 说明: -1 : 一直阻塞,直到有就绪的 Channel 可处理 0 : 不阻塞 0: 表示阻塞多长时间

keys 方法
代码语言:javascript
复制
获取所有注册到 Selector 上的 SelectionKey
 public Set<SelectionKey> keys() {
    if (!isOpen() && !Util.atBugLevel("1.4")) throw new ClosedSelectorException();
        return publicKeys;
}
selectedKeys 方法

获取所有注册到 Selector 上就绪 Channel 的 SelectionKey 信息。

代码语言:javascript
复制
public Set<SelectionKey> selectedKeys() {
    if (!isOpen() && !Util.atBugLevel("1.4")) throw new ClosedSelectorException();
        return publicSelectedKeys;
}

SelectionKey 解析

SelectionKey 类结构如下:

代码语言:javascript
复制
public abstract class SelectionKey {
    protected SelectionKey() { }
    public static final int OP_READ = 1 << 0;
    public static final int OP_WRITE = 1 << 2;
    public static final int OP_CONNECT = 1 << 3;
    public static final int OP_ACCEPT = 1 << 4;
    //附件信息
    private volatile Object attachment = null;
    ....
}
  • public abstract SelectableChannel channel() 获取channel对象
  • public abstract Selector selector() 获取seletor对象
  • public abstract void cancel() 从 Selector 中取消注册该Channel
  • public abstract int interestOps() 获取该chennel 注册到 selector 上的事件
  • public abstract SelectionKey interestOps(int ops) 修改注册到 selector 上的事件
  • public abstract int readyOps() 是否读就绪

读就绪不等于可读,如果没有注册读事件是不能读的。

  • public final boolean isReadable() 判断是否可读
  • public final boolean isWritable() 是否可写
  • public final boolean isConnectable() 是否已经连接
  • public final Object attach(Object ob) 添加附件信息
  • public final Object attachment() 获取附件信息

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.08.20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 相关文章
  • 概述
  • Selector 作用
  • Selector 源码分析
    • register 方法
      • select 方法
        • keys 方法
          • selectedKeys 方法
          • SelectionKey 解析
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档