原创

Java-NIO Selector详解

全网最全 Java 知识点整合总目录入口猛戳-->www.gameboys.cn

Netty 全网最全示例源码地址猛戳-->https://github.com/Sniper2016/NettyStudy

1.Selector的作用是什么?

选择器提供选择执行已经就绪的任务的能力。从底层来看,Selector提供了询问通道是否已经准备好执行每个I/O操作的能力。Selector 允许单线程处理多个Channel。仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道,这样会大量的减少线程之间上下文切换的开销。

2.使用流程:

2.1创建

Selector selector = Selector.open();

2.2.获取通道

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

2.3.设置为非阻塞

serverSocketChannel.configureBlocking(false);

2.4.绑定连接

serverSocketChannel.bind(new InetSocketAddress(SystemConfig.SOCKET_SERVER_PORT));

2.5 将通道注册到选择器上,并制定监听事件为:“接收”事件

serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);

2.6轮询查询就绪操作

while (true) {
 selector.select();
 Set selectedKeys = selector.selectedKeys();
 Iterator 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
  }
  keyIterator.remove();
 }
}

2.7select()方法详解

select()方法,可以查询出已经就绪的通道操作,这些就绪的状态集合,包存在一个元素是SelectionKey对象的Set集合中。

  • int select():阻塞到至少有一个通道在你注册的事件上就绪了。
  • int select(long timeout):和select()一样,但最长阻塞事件为timeout毫秒。
  • int selectNow():非阻塞,立刻返回。

select()方法返回的int值,表示有多少通道已经就绪,更准确的说,是自前一次select方法以来到这一次select方法之间的时间段上,有多少通道变成就绪状态。

3.核心类介绍

3.1 可选择通道(SelectableChannel)

判断一个Channel 能被Selector 复用,有一个前提:判断他是否继承了一个抽象类SelectableChannel。如果继承了SelectableChannel,则可以被复用,否则不能。

SelectableChannel类是何方神圣?

SelectableChannel类提供了实现通道的可选择性所需要的公共方法。它是所有支持就绪检查的通道类的父类。所有socket通道,都继承了SelectableChannel类都是可选择的,包括从管道(Pipe)对象的中获得的通道。而FileChannel类,没有继承SelectableChannel,因此是不是可选通道。

通道和选择器注册之后,他们是绑定的关系吗?

不是一对一的关系。一个通道可以被注册到多个选择器上,但对每个选择器而言只能被注册一次。

通道和选择器之间的关系,使用注册的方式完成。SelectableChannel可以被注册到Selector对象上,在注册的时候,需要指定通道的哪些操作,是Selector感兴趣的。

3.2选择键(SelectionKey)

操作类型有4类:

  • 可读 : SelectionKey.OP_READ = 1 << 0;
  • 可写 : SelectionKey.OP_WRITE = 1 << 2;
  • 连接 : SelectionKey.OP_CONNECT = 1 << 3;
  • 接收 : SelectionKey.OP_ACCEPT = 1 << 4;

Channel和Selector的关系确定好后,并且一旦通道处于某种就绪的状态,就可以被选择器查询到。这个工作,使用选择器Selector的select()方法完成。select方法的作用,对感兴趣的通道操作,进行就绪状态的查询。

Selector可以不断的查询Channel中发生的操作的就绪状态。并且挑选感兴趣的操作就绪状态。一旦通道有操作的就绪状态达成,并且是Selector感兴趣的操作,就会被Selector选中,放入选择键集合中。

一个选择键,首先是包含了注册在Selector的通道操作的类型,比方说SelectionKey.OP_READ。也包含了特定的通道与特定的选择器之间的注册关系。

开发应用程序是,选择键是编程的关键。NIO的编程,就是根据对应的选择键,进行不同的业务逻辑处理。

如果Selector对通道的多操作类型感兴趣,可以用“位或”操作符来实现:int key = SelectionKey.OP_READ | SelectionKey.OP_WRITE ;

正文到此结束