一、Java NIO Selector 基本介绍

  1. JavaNIO,用非阻塞的 IO 方式。可以用一个线程,处理多个的客户端连接,就会使用到 Selector(选择器)。
  2. Selector 能够检测多个注册的通道上是否有事件发生(注意:多个 Channel 以事件的方式可以注册到同一个 Selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求。
  3. 只有在连接/通道真正有读写事件发生时,才会进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程。
  4. 避免了多线程之间的上下文切换导致的开销

文章开头.jpg

二、Java NIO Selector 示意图和特点说明

NIO Selector 介绍(四) - 图2

说明如下:

  1. **Netty****IO** 线程 **NioEventLoop** 聚合了 **Selector**(选择器,也叫多路复用器),可以同时并发处理成百上千个客户端连接。
  2. 当线程从某客户端 **Socket** 通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。
  3. 线程通常将非阻塞 **IO** 的空闲时间用于在其他通道上执行 **IO** 操作,所以单独的线程可以管理多个输入和输出通道。
  4. 由于读写操作都是非阻塞的,这就可以充分提升 **IO** 线程的运行效率,避免由于频繁 **I/O** 阻塞导致的线程挂起。
  5. 一个 **I/O** 线程可以并发处理 **N** 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 **I/O** 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。


三、Java NIO Selector 类相关方法

image.png

  1. //得到一个Selector对象
  2. public static Selector open() throws IOException {
  3. return SelectorProvider.provider().openSelector();
  4. }
  5. public abstract boolean isOpen();
  6. /**
  7. * Tells whether or not this selector is open.
  8. * 判断这个选择器是否打开
  9. * @return <tt>true</tt> if, and only if, this selector is open
  10. */
  11. public abstract boolean isOpen();
  12. /**
  13. * 监控所有的注册的通道,当其中有IO操作可以进行的时候,讲对应得到SelectionKey加入到内部集合中并返回,参数用来设置超时时间
  14. */
  15. public abstract int select(long timeout) throws IOException;
  16. /**
  17. * Returns this selector's selected-key set.
  18. *
  19. * <p> Keys may be removed from, but not directly added to, the
  20. * selected-key set. Any attempt to add an object to the key set will
  21. * cause an {@link UnsupportedOperationException} to be thrown.
  22. *
  23. * <p> The selected-key set is <a href="#ksc">not thread-safe</a>. </p>
  24. *
  25. * @return This selector's selected-key set
  26. *
  27. * @throws ClosedSelectorException
  28. * If this selector is closed
  29. * 从内部集合中得到所有的SelectionKey
  30. */
  31. public abstract Set<SelectionKey> selectedKeys();

其他方法:

  • selector.select(); //阻塞
  • selector.select(1000); //阻塞 1000 毫秒,在 1000 毫秒后返回
  • selector.wakeup(); //唤醒 selector
  • selector.selectNow(); //不阻塞,立马返还