七、Java NIO 选择器
2021-01-19 20:14
标签:组件 包含 color 成功 优化 聚合 ted channels top https://www.cnblogs.com/lay2017/p/12901123.html Java NIO选择器(selector)是一个可以监控一个或多个Channel的组件,监控Channel是否可以read或者write操作。这是一种使得单线程可以管理多个Channel的方法,因此NIO可以使用更少的线程来管理更多的网络连接。 使用单个线程处理多个Channel,可以让你节省线程资源。线程资源的创建、销毁、上下文切换是会增加消耗的。因此,我们需要使用更少的线程来做优化。使用选择器可以做到节省线程,如图 创建一个选择器通过调用open方法 为了在selector中选择Channel,你需要先将Channel注册到selector当中。通过register方法 Channel必须是非阻塞模式,否则将不生效。 注意到register方法的第二个参数,指明了你要监听该Channel的什么事件: 1.Connect:连接成功 2.Accept:ServerChannelSocket收到连接 3.Read:可以读取 4.Write:可以写入 事件对应的参数分别是 1.SelectionKey.OP_CONNECT 2.SelectionKey.OP_ACCEPT 3.SelectionKey.OP_READ 4.SelectionKey.OP_WRITE 如果你想监听多个事件,那么可以这样 当你把一个Channel注册到Selector当中,register方法会返回一个SelectionKey对象。这个SelectionKey对象包含了一些东西,如下: 1.interest set 2.ready set 3.channel 4.selector 5.attached object(可选) 下面一一说明 interest set是一个事件集合,包含了selector你响应监听的事件。你可以通过以下方式来判断哪些事件是你关注的 ready set包含了哪些操作你可以执行,这可能会是你比较常用的,如 你可以和interest set一样通过readySet值的位与来得出哪些操作可以执行,也可以直接调用方法 你可以把一个对象关联到SelectionKey。例如你可以把Channel对应的Buffer关联,或者把聚合数据对象关联 你还可以在register的时候关联 一旦你把Channel都注册到了Selector当中,你就可以调用select方法。select方法如 1.int select():阻塞等待,直到至少一个Channel响应事件 2.int select(long timeout):和select类似,但是增加了一个最大超时时间 3.int selectNow():不阻塞,直接返回 int返回值返回的是当前有多少个Channel有响应事件。注意,它返回的是你上一次调用select到当前时间有多少个。例如: 你调用了一次select,返回1,表示一个Channel响应。然后你再调用select,又返回1,表示一个新的Channel响应。如果第一个Channel响应的时候,你没有做任何事情那么当前是有两个Channel响应,但是select只返回了1。 select方法只知道当前有新的Channel响应事件,但不知道总共有多少个。可以通过调用selectedKeys来获取总共多少个 当你注册一个Channel到Selector,register方法会返回SelectionKey。其实,你可以通过selectedKeySet方法获取,然后,你可以迭代SelectionKey,去操作准备好的Channel 注意一下remove方法,Selector本身并没有移除SelectionKey的实现。你需要代替Selector来做这件事。当你处理完Channel以后,你需要调用remove来移除。而如果这个Channel又响应事件,它会重新添加SelectedKey。 当一个线程调用了select方法以后会被阻塞,那么如果你想停止这种阻塞你可以启动另外一个线程调用Selector.wakeup()方法,那么当前阻塞的线程都将不阻塞,并且新的线程调用select方法也不会阻塞 如果你想关闭Selector,那么就调用close方法。这个方法会使得所有SelectionKey失效。但是注意,Channel并没有关闭。 下面是一个完整示例 七、Java NIO 选择器 标签:组件 包含 color 成功 优化 聚合 ted channels top 原文地址:https://www.cnblogs.com/lay2017/p/12906313.html所有文章
正文
为什么使用selector?
创建一个选择器
Selector selector = Selector.open();
注册Channel到选择器当中
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
SelectionKey
Interest Set
int interestSet = selectionKey.interestOps();
boolean isInterestedInAccept = interestSet & SelectionKey.OP_ACCEPT;
boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT;
boolean isInterestedInRead = interestSet & SelectionKey.OP_READ;
boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE;
Ready Set
int readySet = selectionKey.readyOps();
selectionKey.isAcceptable();
selectionKey.isConnectable();
selectionKey.isReadable();
selectionKey.isWritable();
Channel和Selector
Channel channel = selectionKey.channel();
Selector selector = selectionKey.selector();
Attaching Object
selectionKey.attach(theObject);
Object attachedObj = selectionKey.attachment();
SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject);
通过Selector选择Channel
selectedKeys
Set
Set
wakeUp
close
Selector的完整示例
// 创建一个Selector
Selector selector = Selector.open();
// Channel设置为非阻塞
channel.configureBlocking(false);
// channel注册到Selector,监听read事件
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
// 死循环
while(true) {
// 开始select操作
int readyChannels = selector.selectNow();
// 如果没有Channel响应,跳过
if(readyChannels == 0) continue;
// 有Channel响应,获取SelectionKey
Set