从Java NIO到Netty(二)

Java NIO组件介绍

Selector

Selector 能够检测一个或多个Channel是否已经准备好读或写等事件。这样,一个线程就可以管理多个Channel(要知道对于操作系统来讲,频繁切换线程代价是十分昂贵的)。下面是一个Selector处理3个Channel的示意图:

image.png

1 创建Selector

Selector selector = Selector.open();
复制代码

2 将channel注册到Selector上

//channel必须设置为非阻塞模式才能够搭配Selector使用
channel.configureBlocking(false);
//第二个参数为感兴趣的事件集合
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
复制代码

事件集合有四种,可以通过或操作注册多个感兴趣事件:

  • SelectionKey.OP_CONNECT
  • SelectionKey.OP_ACCEPT
  • SelectionKey.OP_READ
  • SelectionKey.OP_WRITE
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE; 
复制代码

3 注册完返回参数SelectionKey

首先介绍SelectionKey包括的属性:

  • The interest set:感兴趣的事件集合
  • The ready set:哪些事件已经准备好了
  • The Channel:注册时的Channel
  • The Selector:注册时的Selector
  • An attached object (optional):附加对象

4 通过Selector选择Channel

如果注册了多个Channel到Selector可以通过select()来得到已经准备好的Channels(即一个或多个Channel中已经有感兴趣事件触发了)。

  • int select():一直阻塞一直有Channel准备好
  • int select(long timeout):在指定时间内阻塞一直到Channel准备好
  • int selectNow():不阻塞,马上返回,不管Channel有没有准备好

其中返回值int代表有多少个Channel准备好
知道有Channel准备好后,可以通过 selectedKeys()方法获取准备好的Channel:

Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {  
    SelectionKey key = keyIterator.next();
    if(key.isAcceptable()) {
        // a connection was accepted by a ServerSocketChannel.
    } else if (key.isConnectable()) {
        // a connection was established with a remote server.
    } else if (key.isReadable()) {
        // a channel is ready for reading
    } else if (key.isWritable()) {
        // a channel is ready for writing
    }
    //必须在处理完通道时自己移除SelectionKey,否则下次该通道变成就绪时,Selector会再次将其放入已选择键集中。
    keyIterator.remove();
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享