生活中例子告诉你:Java NIO复用器Selectors

简介: 生活中例子告诉你:Java NIO复用器Selectors

复用器有能力做就绪事件选择,驱动I/O复用。这样能够让单个线程高效地并发管理多个网络I/O通道。C/C++网络编程库拥有POSIX select() 或者poll()系统调用已经有很多年。但直到Jdk1.4,Java编程人员才能够使用网络就绪选择的功能。


一,用形象的例子理解Selectors


Java中Selectors及其相关类的作用相当于下图多路选择器的功能。通过a、b值的选择达到输入A、B、C、D其中一路可以进行Q输出的功能。

image.png

下图是多路选择器芯片。

1665752266261.jpg

如果这个还不够形象。Ok,再来一波教科书上的介绍。


  1. 正如Java NIO1一书中介绍的例子所述。想象一下有三个直通业务窗口的银行。在传统(非复用)场景中,假设每个业务窗口都有一个通道(channel),该通道通向银行的出纳员柜台,每个出纳员柜台都与其他出纳员柜台隔离。这意味着每个通道(channel)需要专用的出纳员(worker thread)。 这种方法不能很好地扩展并且是浪费的。对于每个添加的新通道,都需要一个新的柜员,以及相关的开销,如桌子、椅子、回形针(内存、CPU周期、上下文切换)等。当事情进展缓慢时,这些资源往往是闲置的。
  2. 现在想象一个不同的场景,其中通道连接到银行内的出纳员柜台。 该柜台有三个插槽,业务(data buffer)到达,每个插槽都有一个指示灯(selection key),当业务位于插槽中时,指示灯亮起。 再想象一下出纳员(worker thread)有一个手机,并花费尽可能多的时间看手机。在十分钟后,出纳员向上看指示灯(调用select())以确定是否有任何通道准备就绪(readiness selection)。当直通车道(通道)处于空闲状态,出纳员(worker thread)可以执行另一项任务。但在需要注意时仍能及时响应。
  3. 一个更准确的例子,自己可以想象一下现在的餐厅,老板、服务员、顾客和厨师的关系。


二,Selectors 基础


  1. 用对象selector注册一个至多个可选择的通道(channel)。一个key值表示返回的一个通道(channel)和一个选择(selector)的关系。Selection keys能够记住你对每个通道感兴趣的键值。Selection keys也能够追踪通道(channel)现在能够执行的兴趣操作。在对象selector上调用select()时,通过检查使用该选择器注册的所有通道来更新关联的键。你能够获得key值的set集合,进而迭代这些key值来服务在上一次调用select()时产生的所有已经就绪通道(channel)。
  2. 这是从上层看了鸟瞰了Selectors基础,接下来进行底层剖析。
  3. 在最基本的层面上,Selectors提供了询问通道是否已准备好执行您感兴趣的I/O操作的功能。例如,可以询问SocketChannel对象是否有任何准备好读取的字节,或者我们可能想知道ServerSocketChannel是否有任何准备接受的传入连接。
  4. Selectors与SelectableChannel对象一起使用时提供此服务,但故事的内容不止于此。readiness selection的真正力量是可以同时检查潜在的大量通道的准备情况。调用者可以轻松确定几个通道(channel)中的哪一个已准备就绪。可选地,调用线程可以要求其进入休眠状态,直到用Selectors注册的一个或多个通道准备就绪,或者可以周期性地轮询选择器以查看自上次检查以来是否有任何准备就绪。如果你想需要一个必须管理大量并发连接的Web服务器,很容易想象如何充分利用这些功能。
  5. 乍一看,似乎可以单独使用非阻塞模式模拟readiness selection,但实际上并非如此。非阻塞模式将执行请求的操作或指示它不执行。这在语义上与确定是否可以执行某种类型的操作不同。例如,如果尝试非阻塞读取并且成功,则不仅可以发现read(),还可以读取一些数据。然后,必须对该数据执行某些操作。
  6. 这有效地防止了将检查通道准备就绪的代码与处理数据的代码分开,至少没有明显的复杂性。即使可以简单地询问每个通道(channel)是否准备就绪,这仍然会有问题,因为你的代码或库包中的某些代码需要遍历所有候选通道(channel)并依次检查每个通道(channel)。这将导致每个通道(channel)至少有一个系统调用来查看其准备情况,这可能很昂贵,但主要问题是检查不是原子性的(多线程应用)。列表(list)中的早期通道(channel)可以在检查后准备就绪,但在下次轮询(poll)之前不会知道它是否可用。最糟糕的是,你别无选择,只能继续轮询列表(list)。当你感兴趣的频道准备就绪时,你将无法立即获得通知。
  7. 这就是为什么监视多个socket的传统Java解决方案是为每个socket创建一个线程,并允许线程在read()中阻塞,直到数据可用。这有效地让每个被阻塞的线程成socket监视器,并且JVM的线程调度程序成为通知机制。管理所有这些线程的复杂性和性能成本,对于程序员和JVM来说,随着线程数量的增长而迅速失控。
  8. 真正的readiness selection必须由操作系统完成。操作系统执行的最重要功能之一是处理I/O请求并在数据准备就绪时通知进程。因此,将此功能委托给操作系统才有意义。Selector类提供抽象,通过该抽象,Java代码可以便携地从底层操作系统请求readiness selection服务。


三,Selectors 相关类


下面来理清Selectors 相关类怎样实现交互完成readiness selection功能的。主要有三个相关类。


  1. Selector:该类管理有关一组注册通道及其readiness selection的信息。 通道向选择器注册,并且可以要求选择器更新当前向其注册的通道(channel)的准备状态。这样做时,调用线程可以指示它暂停,直到其中一个已注册的通道准备就绪。
  2. SelectableChannel:此抽象类提供了实现通道选择性所需的常用方法。它是支持readiness selection功能的所有通道类的超类。FileChannel对象不可选,因为它不从SelectableChannel扩展。所有套接字通道类都是可选的,以及从Pipe对象获得的通道。可以使用Selector对象注册SelectableChannel对象,并指示该通道上哪些操作对该选择器感兴趣。通道注册到多个选择器上,但每个选择器只能注册一次。
  3. SelectionKey:该类封装特定通道和特定选择器之间的注册关系。SelectionableChannel.register()返回SelectionKey对象,并用作表示注册的标记。SelectionKey对象包含两个位(编码为整数),指示注册者对哪些通道操作感兴趣以及通道准备执行哪些操作。


https://item.jd.com/1105633702.html ↩︎


相关文章
|
7天前
|
存储 监控 Java
深入探索Java语言的NIO(New I/O)技术
深入探索Java语言的NIO(New I/O)技术
|
8天前
|
存储 监控 Java
Java nio非阻塞io
Java nio非阻塞io
|
23天前
|
监控 Java
Java一分钟之-NIO:非阻塞IO操作
【5月更文挑战第14天】Java的NIO(New IO)解决了传统BIO在高并发下的低效问题,通过非阻塞方式提高性能。NIO涉及复杂的选择器和缓冲区管理,易出现线程、内存和中断处理的误区。要避免这些问题,可以使用如Netty的NIO库,谨慎设计并发策略,并建立标准异常处理。示例展示了简单NIO服务器,接收连接并发送欢迎消息。理解NIO工作原理和最佳实践,有助于构建高效网络应用。
19 2
|
23天前
|
Java 编译器 开发者
Java一分钟之-继承:复用与扩展类的特性
【5月更文挑战第9天】本文探讨了Java中的继承机制,通过实例展示了如何使用`extends`创建子类继承父类的属性和方法。文章列举了常见问题和易错点,如构造器调用、方法覆盖、访问权限和类型转换,并提供了解决方案。建议深入理解继承原理,谨慎设计类结构,利用抽象类和接口以提高代码复用和扩展性。正确应用继承能构建更清晰、灵活的代码结构,提升面向对象设计能力。
21 0
|
23天前
|
设计模式 存储 Java
[设计模式Java实现附plantuml源码~结构型]实现对象的复用——享元模式
[设计模式Java实现附plantuml源码~结构型]实现对象的复用——享元模式
|
23天前
|
缓存 Java API
Java NIO和IO之间的区别
NIO(New IO),这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
19 1
|
23天前
|
监控 Java 开发者
深入理解 Java 网络编程和 NIO
【4月更文挑战第19天】Java网络编程基于Socket,但NIO(非阻塞I/O)提升了效率和性能。NIO特点是非阻塞模式、选择器机制和缓冲区,适合高并发场景。使用NIO涉及通道、选择器和事件处理,优点是高并发、资源利用率和可扩展性,但复杂度、错误处理和性能调优是挑战。开发者应根据需求选择是否使用NIO,并深入理解其原理。
|
23天前
|
存储 监控 Java
浅谈Java NIO
浅谈Java NIO
9 0
|
11月前
|
Java
Java NIO系列教程三
​ 今天主要给大家介绍的是Buffer的基本使用这个也是NIO里面最总要的概率之一,里面的操作也是有一些复杂的同时也是需要大家必须要重点掌握的知识点,同时也介绍了一下Selector的用法下一篇文章我们将为大家介绍Pipe管道以及FileLock文件锁这也是NIO里面最后的一分部内容了。
83 0
|
11月前
|
安全 Java API
Java NIO系列教程四【完】-管道-文件锁-异步写入
​ 到此位置NIO的所有的内容都结束了,对于NIO来说主要是各种概念需要大家去理解然后有很多的用法和api也需要大家去熟悉所以想把NIO学懂学好其实并不容易一定要多写案例去测试巩固,也预祝大家能把NIO的知识看懂理顺!!!
83 0