NIO 之 ByteBuffer实现原理
NIO 之 Channel实现原理
BIO、NIO、AIO 内部原理分析服务器
Selector容许单线程处理多个 Channel。若是你的应用打开了多个链接(通道),但每一个链接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。ide
这是在一个单线程中使用一个Selector处理3个Channel的图示:源码分析
selector与channel关系spa
要使用Selector,得向Selector注册Channel,而后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就能够处理这些事件,事件的例子有如新链接进来,数据接收等。操作系统
仅用单个线程来处理多个Channels的好处是,只须要更少的线程来处理通道。事实上,能够只用一个线程处理全部的通道。对于操做系统来讲,线程之间上下文切换的开销很大,并且每一个线程都要占用系统的一些资源(如内存)。所以,使用的线程越少越好。
Selector可以在单个线程中处理多个通道,这样能够减小多个线程形成上下文切换问题。.net
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的几个方法3d
该方法是在 Channel的register方法中调用的。具体详见NIO 之 Channel实现原理rest
register 方法code
这四种事件用SelectionKey的四个常量来表示:
SelectionKey.OP_CONNECT
SelectionKey.OP_ACCEPT
SelectionKey.OP_READ
SelectionKey.OP_WRITE
不一样的 Channel 注册到 Selector 后,就能够随时查询 Selector ,找出哪些 Channel 已经准备好能够进行处理。Channel 可能准备好上面注册到 Selector 感兴趣事件中的一个或多个。
public int select() throws IOException { return select(0); }
public int select(long timeout) throws IOException { if (timeout < 0) throw new IllegalArgumentException("Negative timeout"); return lockAndDoSelect((timeout == 0) ? -1 : timeout); }
public int selectNow() throws IOException { return lockAndDoSelect(0); }
上面三个 select方法底层都是调用 lockAndDoSelect 方法。
lockAndDoSelect方法的参数值 说明:
-1 : 一直阻塞,直到有就绪的 Channel 可处理
0 : 不阻塞
timout>0: 表示阻塞多长时间(timeout)
获取全部注册到 Selector 上的 SelectionKey public Set<SelectionKey> keys() { if (!isOpen() && !Util.atBugLevel("1.4")) throw new ClosedSelectorException(); return publicKeys; }
获取全部注册到 Selector 上就绪 Channel 的 SelectionKey 信息。
public Set<SelectionKey> selectedKeys() { if (!isOpen() && !Util.atBugLevel("1.4")) throw new ClosedSelectorException(); return publicSelectedKeys; }
SelectionKey 类结构以下:
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() 获取附件信息