Selector
要实现异步IO要通过Selector,甚至我们可以通过一个线程管理多个Channel的读写,这是NIO相较BIO的优越之处之一。
Channel可以注册到一个Selector上,Selector可以监视多个Channel的状态
Channel的状态有四种:
- CONNECT
- ACCEPT
- READ
- WRITE
CONNECT
代表某个Channel成功连接到另一个服务器(客户端)。ACCEPT
则是一个ServerSocketChannel准备好接收新连接(服务端)。READ
代表该Channel有数据可读,WRITE
代表该Channel等待写操作。
这些状态在Java中对应SelectionKey中的四个常量
- SelectionKey.OP_CONNECT
- SelectionKey.OP_ACCEPT
- SelectionKey.OP_READ
- SelectionKey.OP_WRITE
在给Channel注册到Selector时可以指定要监听的状态:
channel.configureBlocking(false);
SelectionKey key =channel.register(selector,SelectionKey.OP_READ);
这个状态可以是多个状态合成的,我们叫它interestOps
,是任意几个状态的位或结果。
register方法可以返回一个SelectionKey,作为注册在该Selector上的Channel的唯一标识(一个Selector-Channel对)。
Selector的常用API:
int select()
:阻塞等待,直到至少有一个绑定的Channel符合监听的状态,返回符合状态Channel的个数,也可能是0(如果中途有一个Key的interestOps被更新了)。int select(long timeout)
:阻塞等待限制一个最长时间,超过时间直接返回。int selectNow()
:不阻塞,直接查询有几个符合监听状态的Channel。Set<SelectionKey> selectedKeys()
:经过任一select操作后可以获取被select到的keys。Selector wakeup()
:如果一个线程调用select()
方法阻塞了,可以让另一个线程调用同一个Selector上的wakeup()
方法来唤醒这个线程。void close()
:关闭这个Selector。
SelectionKey
SelectionKey的常用API:
int interestOps()
:返回interestOps,可以通过与常量进行位与来判断是否含有某个状态。int readyOps()
:返回的是有哪些监听的状态目前是对应的,也是合成值,可以通过与常量进行位与来判断是否含有某个状态。或者直接调用isConnectable
,isAcceptable
,isReadable
,isWritable
。SelectableChannel channel()
:获取这个SelectionKey对应的ChannelSelector selector()
: 获取这个SelectionKey对应的SelectorObject attach(Object ob)
:给这个SelectionKey附加一个Object对象Object attachment()
:获取这个附加的Object对象
原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/nio%e7%bd%91%e7%bb%9c%e7%bc%96%e7%a8%8b%e4%b9%8bselector%e4%bb%8b%e7%bb%8d/