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<SelectionKey> keys();
/**
* 被选择的SelectionKey结合,返回此Selector的已选择键集,注册到Selector上发生事件的Channel集合
*/
public abstract Set<SelectionKey> 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; }
}

被折叠的 条评论
为什么被折叠?



