生活中例子告诉你: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 ↩︎


相关文章
|
3月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
17天前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
22天前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
37 3
|
22天前
|
Java 数据库连接 数据库
深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能
在Java应用开发中,数据库操作常成为性能瓶颈。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能。文章介绍了连接池的优势、选择和使用方法,以及优化配置的技巧。
22 1
|
1月前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
30 2
|
2月前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
3月前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
86 2
|
3月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
118 0
|
4月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
165 1
|
3月前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
73 0