6、Selector
(1)、特点
Selector(选择器)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。即用选择器,借助单一线程,就可对数量庞大的活动I/O通道实施监控和维护。
①、Netty的IO线程NioEventLoop聚合了Selector(选择器,也叫多路复用器),可以同时并发处理成百上千个客户端连接。
②、当线程从某客户端Socket通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。
③、线程通常将非阻塞IO的空闲时间用于在其他通道上执行IO操作,所以单独的线程可以管理多个输入和输出通道。
④、由于读写操作都是非阻塞的,这就可以充分提升IO线程的运行效率,避免由于频繁I/O阻塞导致的线程挂起。
⑤、一个I/O线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞I/O一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。
(2)、核心方法
①、open()方法
得到一个Selector对象
②、selectedKeys()方法
从内部集合中得到所有的SelectionKey,注册到Selector上发生事件的Channel集合
③、select()方法 / select(long timeout)方法(阻塞方法)
监控所有注册的通道,当其中有IO操作(事件发生)时,该方法返回,并将对应的SelectionKey加入到被选择的SelectionKey集合中,该方法返回这些Channel的数量。
④、wakeup()
唤醒selector,使一个还未返回的select()方法立即返回。
⑤、selectNow()(非阻塞)
执行一个立即返回的select()操作。
- public abstract class Selector implements Closeable {
- /**
- * 得到一个Selector对象
- */
- public static Selector open() throws IOException {return SelectorProvider.provider().openSelector();}
- /**
- * 获取所有的SelectionKey集合,代表注册在该Selector上的所有Channel的SelectionKey
- */
- public abstract Set
keys(); - /**
- * 被选择的SelectionKey结合,返回此Selector的已选择键集,注册到Selector上发生事件的Channel集合
- */
- public abstract Set
selectedKeys(); - /**
- * 监控所有注册的Channel,当它们中间有需要处理的IO操作时,该方法返回,并将对应的SelectionKey加入被选择的SelectionKey集合中,该方法返回这些Channel的数量
- */
- public abstract int select() throws IOException;
- /**
- * 可以设置超时时长的Select()操作
- */
- public abstract int select(long timeout) throws IOException;
- /**
- * 使一个还未返回的select()方法立即返回
- */
- public abstract Selector wakeup();
- /**
- * 执行一个立即返回的select()操作,该方法不会阻塞线程
- */
- public abstract int selectNow() throws IOException;
- /**
- * 关闭连接器
- */
- public abstract void close() throws IOException;
- }
(3)、SelectionKey
①、概述
SelectionKey为选择键,表示SelectableChannel和Selector之间的注册关系,每次向选择器注册通道时就会选一个事件(选择键)。选择键包含两个表示为整数值的操作集。操作集的每一位都表示该键的通道所支持的一类可选择操作。
②、register(Selector sel, int ops):sel为Selector;ops为SelectionKey
若注册时不止监听一个事件(选择键),则可以使用“位或”操作符连接。
例:int ops = SelectionKey.OP_READ|SelectionKey.OP_WRITE;
③、源码解析
- public abstract class SelectionKey {
- /**
- * 读操作:OP_READ = 1
- */
- public static final int OP_READ = 1 << 0;
- /**
- * 写操作:OP_READ = 4
- */
- public static final int OP_WRITE = 1 << 2;
- /**
- * 连接操作:OP_READ = 8
- */
- public static final int OP_CONNECT = 1 << 3;
- /**
- * 接收操作:OP_READ = 16
- */
- public static final int OP_ACCEPT = 1 << 4;
- /**
- * 得到与之关联的channel
- */
- public abstract SelectableChannel channel();
- /**
- * 得到与之关联的Selector对象
- */
- public abstract Selector selector();
- /**
- * 得到与之关联的共享数据
- */
- public final Object attachment() {return attachment;}
- /**
- * 设置或改变监听事件,并返回SelectionKey对象
- */
- public abstract SelectionKey interestOps();
- /**
- * 获取通道已经准备就绪的操作的集合
- */
- public abstract int readyOps();
- /**
- * 检测Channel中读事件是否就绪
- */
- public final boolean isReadable() {
- return (readyOps() & OP_READ) != 0;
- }
- /**
- * 检测Channel中写事件是否就绪
- */
- public final boolean isWritable() {
- return (readyOps() & OP_WRITE) != 0;
- }
- /**
- * 检测Channel中连接是否就绪
- */
- public final boolean isConnectable() {
- return (readyOps() & OP_CONNECT) != 0;
- }
- /**
- * 检测Channel中接收是否就绪
- */
- public final boolean isAcceptable() { return (readyOps() & OP_ACCEPT) != 0; }
- }