8.JAVA NIO核心之选择器(Selector)

news2025/2/22 3:39:53

highlight: arduino-light

选择器(Selector)概述

选择器Selector是 SelectableChannle 对象的多路复用器,Selector 可以同时监控多个SelectableChannel的 IO 状况,也就是说,利用 Selector可使一个单独的线程管理多个 Channel。Selector 是非阻塞 IO 的核心

image.png

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

1.ServerSocketChannel会和Selector绑定

2.所有的SocketChannel请求连接ServerSocketChannel上,表明自己监听事件类型。

3.Selector会监听SocketChannel,返回一个 SelectionKey, 会和该Selector 关联(集合)

4.当有事件发生时,可以遍历所有的SelectKey,判断是否是对应的监听事件类型

在通过 SelectionKey 反向获取 SocketChannel , 方法 channel()

5.如果是 那么就做处理。

isAcceptable() isReadable() isWritable()

以服务端A,客户端B、C为例,

1.A绑定一个Selector,并启动

2.B请求A,A注册事件到Selector(即接收、读、写),加入到SelectKeys

3.C请求A,A注册事件到Selector(即接收、读、写),加入到SelectKeys

4.服务端A空转判断是否有事件发生,如果有事件发生

while (selector.select() > 0){

//从SelectKeys获取所有的SelectKey

//判断SelectKey事件类型

//做对应处理即可

}

如果B注册了读,那么B向A发送数据会触发selector.select() > 0的判断,并且B对应的SelectKey的isReadable是true

Selector相关API

Selector 类是一个抽象类, 常用方法和说明如下:

java public abstract class Selector implements Closeable { //得到一个选择器对象,真实类型是WindowSelectorImpl,不同操作系统selector类型不一样 public static Selector open(); public int select(long timeout);//监控所有注册的通道,返回有事件发生的通道的个数.当其中有 IO 操作可以进行时,将对应的 SelectionKey 加入到内部集合中并返回,参数用来设置超时时间 ​ public int select();//相当于select(0)返回有事件发生的通道的个数.当其中有 IO 操作可以进行时,将对应的 SelectionKey 加入到内部集合中并返回 ​ public Set<SelectionKey> keys();//从内部集合中得到所有的 SelectionKey     public Set<SelectionKey> selectedKeys();//有事件发生的 SelectionKey }

SelectionKey常量

表示 Selector 和网络通道的注册关系, 共四种:

int OP_ACCEPT:有新的网络连接可以 accept,值为 16

int OP_CONNECT:代表连接已经建立,值为 8

int OP_READ:代表读操作,值为 1

int OP_WRITE:代表写操作,值为 4

源码中:

public static final int OP_READ = 1 << 0;

public static final int OP_WRITE = 1 << 2;

public static final int OP_CONNECT = 1 << 3;

public static final int OP_ACCEPT = 1 << 4;

SelectionKey方法

java public abstract class SelectionKey {     public abstract Selector selector();//得到与之关联的 Selector 对象     public abstract SelectableChannel channel();//得到与之关联的通道     public final Object attachment();//得到与之关联的共享数据     public abstract SelectionKey interestOps(int ops);//设置或改变监听事件     public final boolean isAcceptable();//是否可以 accept     public final boolean isReadable();//是否可以读     public final boolean isWritable();//是否可以写 }

Selector流程说明

java 对下图的说明: 当客户端连接时,会通过ServerSocketChannel 得到 SocketChannel Selector通过select 方法进行监听,返回有事件发生的通道的个数. ​ 将socketChannel注册到Selector上, register(Selector sel, int ops), 一个selector上可以注册多个SocketChannel ​ 注册后返回一个 SelectionKey, 会和该Selector 关联(集合) 进一步得到各个 SelectionKey (有事件发生) 在通过 SelectionKey 反向获取 SocketChannel ,通过channel()方法 得到的 channel , 完成业务处理

选择器(Selector)的应用

java //1. 获取通道 ServerSocketChannel ssChannel = ServerSocketChannel.open(); //2. 切换非阻塞模式 ssChannel.configureBlocking(false); //3. 绑定连接 ssChannel.bind(new InetSocketAddress(9898)); //4. 获取选择器 Selector selector = Selector.open(); //5. 将通道注册到选择器上, 并且指定“监听接收事件” ssChannel.register(selector, SelectionKey.OP_READ); //监听多个时间 //ssChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);

当调用 register(Selector sel, int ops) 将通道注册选择器时,选择器对通道的监听事件,需要通过第二个参数 ops 指定。可以监听的事件类型(用 可使用 SelectionKey 的四个常量 表示):

  • 读 : SelectionKey.OP_READ (1)
  • 写 : SelectionKey.OP_WRITE (4)
  • 连接 : SelectionKey.OP_CONNECT (8)客户端监听
  • 接收 : SelectionKey.OP_ACCEPT (16)
  • 若注册时不止监听一个事件,则可以使用“位或”操作符连接。
  • 若想修改监听事件:例如修改为写事件调用selectionKey.interestOps(SelectionKey.OP_WRITE )

java int interestSet = SelectionKey.OP_READ|SelectionKey.OP_WRITE

  • OP_READ 数据已经筹备好了,能够读了,也成为了读就绪。
  • OP_WRITE 已经能够通过通道向缓冲区中写数据了,也称为写就绪。
  • OP_CONNECT 连接已就绪
  • OP_ACCEPT 服务端曾经监听到了客户端发动的连接申请,能够与服务端建立连接的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/792309.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

shift语句的使用

[rootvm1 scripts]# help shift shift: shift [n]Shift positional parameters.Rename the positional parameters $N1,$N2 ... to $1,$2 ... If N isnot given, it is assumed to be 1.Exit Status:Returns success unless N is negative or greater than $#.说明&#xff1a…

SWMM模型:水文水动力模型在城市内涝、城市排水、海绵城市规划设计中深度应用

查看原文>>>最新水文水动力模型在城市内涝、城市排水、海绵城市规划设计中深度应用 随着计算机的广泛应用和各类模型软件的发展&#xff0c;将排水系统模型作为城市洪灾评价与防治的技术手段已经成为防洪防灾的重要技术途径。本文聚焦于综合利用GIS及CAD等工具高效地进…

Rust vs Go:常用语法对比(十二)

题图来自 Rust vs Go in 2023[1] 221. Remove all non-digits characters Create string t from string s, keeping only digit characters 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. 删除所有非数字字符 package mainimport ( "fmt" "regexp")func main() { s : hei…

07 |「注解、反射、多线程、锁」

前言 函数 文章目录 前言一、注解二、反射1、作用 三、多线程1、基本概念2、实现方式1&#xff09;继承 Thread 类2&#xff09;实现Runnable接口3、常用 API 四、锁1、为什么2、锁 一、注解 注解不影响程序逻辑&#xff0c;但会被编译器在不同阶段&#xff08;编译、执行&…

【小白必看】利用Python生成个性化名单Word文档

文章目录 前言所需文件及文件格式说明excel数据如下word 模板如下文件目录格式及生成后的文件 导入所需的模块&#xff1a;打开 Excel 文件&#xff1a;选择工作表&#xff1a;获取数据列表&#xff1a;遍历数据并生成 Word 文档&#xff1a;完整代码结束语 前言 对于需要批量…

【Python机器学习】实验03 logstic回归

文章目录 简单分类模型 - 逻辑回归1.1 准备数据1.2 定义假设函数Sigmoid 函数 1.3 定义代价函数1.4 定义梯度下降算法gradient descent(梯度下降) 1.5 绘制决策边界1.6 计算准确率1.7 试试用Sklearn来解决2.1 准备数据(试试第二个例子)2.2 假设函数与前h相同2.3 代价函数与前相…

找不到vcruntime140_1.dll,无法继续执行此代码如何解决

最近我在使用电脑时遇到了一个问题&#xff0c;即出现了vcruntime140_1.dll文件丢失的错误提示。这让我感到非常困惑和烦恼&#xff0c;因为我无法正常运行一些软件和游戏。 vcruntime140_1.dll是一个Windows系统文件&#xff0c;它是Microsoft Visual C Redistributable的一部…

maven本地仓库地址修改+maven国内镜像设置+maven运行所需pos.xml文件配置基本写法

1&#xff0c;maven本地仓库地址修改 maven在使用过程中&#xff0c;本地项目仓库其空间占用会越来越大&#xff0c;但是其默认仓库位置往往是以C盘为主&#xff0c;C盘作为系统盘常常会遇到所在盘空间占满的情况&#xff0c;所以我们将其改至其他硬盘空间位置为适合做法&#…

Vue style中的 scoped 属性

Vue 中存在 scoped 属性&#xff0c;HTML5中也存在一个 scoped 属性&#xff0c;而且&#xff0c;这两者都是针对 css 样式处理的属性&#xff0c;所以很多文章在 解释 Vue scoped 的时候&#xff0c;都会把两者混为一谈&#xff0c;直接进把 HTML5 scoped 的定义搬到 Vue scop…

TikTok带货成功的关键:用户参与与互动

TikTok作为一个社交媒体平台&#xff0c;其带货成功的关键之一是用户参与和互动。在这篇文章中&#xff0c;我们将探讨如何通过激发用户参与和互动&#xff0c;提高TikTok带货的效果。 首先&#xff0c;创造互动性的内容是吸引用户参与的重要因素。在带货视频中&#xff0c;可…

Redis学习路线(1)—— Redis的安装

一、NoSQL SQL VS NoSQL 1、名称 SQL 主要是指关系数据库。NoSQL 主要是指非关系数据库。 2、存储结构 SQL 是结构化的数据库&#xff0c;以表格的形式存储数据。NoSQL 是非结构化的数据库&#xff0c;以Key-Value&#xff08;Redis&#xff09;&#xff0c;JSON格式文档&…

Linux系统安装Mysql二进制文件

&#x1f4bb;前言 为了简化安装和配置过程&#xff0c;许多Linux发行版提供了预编译的二进制MySQL安装包&#xff0c;这些安装包已经经过测试和验证&#xff0c;可以在大多数Linux系统上正常工作。通过安装这些二进制MySQL安装包&#xff0c;可以省去从源代码编译和安装的繁琐…

mysql通过binlog恢复数据

开启binlog 在my.ini中添加以下两行代码&#xff1a; log-binmysql-bin server-id1 注意要写在[mysqld]范围内才会生效 查看binlog存放日志文件目录 show variables like %datadir%; 查看binlog文件名 show master logs; 将binlog转换成sql mysqlbinlog --no-defaults …

个性化-强连接-更智能 伙伴云5大扩展功能详解

伙伴云【小伙开麦】直播间「“伙”速上新」栏目上线&#xff0c;由产品经理讲解产品伙伴云5大功能模块&#xff0c;旨在让业务流程更加清晰、让用户使用操作更加便捷、让业绩转化更高效、让生态连接更顺畅…… 在不断的技术创新过程中&#xff0c;进一步助力数字化转型&#x…

CAN bus off ——ISO11898

什么是can bus off&#xff1f; CAN总线关闭&#xff08;CAN bus off&#xff09;是指CAN节点进入一种错误状态&#xff0c;无法继续正常的数据通信。当一个CAN节点的错误计数器超过了设定的阈值时&#xff0c;该节点将进入CAN总线关闭状态。在这种状态下&#xff0c;该节点将停…

opencv-24 图像几何变换03-仿射-cv2.warpAffine()

什么是仿射&#xff1f; 仿射变换是指图像可以通过一系列的几何变换来实现平移、旋转等多种操作。该变换能够 保持图像的平直性和平行性。平直性是指图像经过仿射变换后&#xff0c;直线仍然是直线&#xff1b;平行性是指 图像在完成仿射变换后&#xff0c;平行线仍然是平行线。…

Android 耗时分析(adb shell/Studio CPU Profiler/插桩Trace API)

1.adb logcat 查看冷启动时间和Activity显示时间&#xff1a; 过滤Displayed关键字&#xff0c;可看到Activity的显示时间 那上面display后面的是时间是指包含哪些过程的时间呢&#xff1f; 模拟在Application中沉睡1秒操作&#xff0c;冷启动情况下&#xff1a; 从上可知&…

Python小练习实践

在交互模式下&#xff0c;可以不写print&#xff1b;默认调用 print(repr(a)) 文件模式&#xff0c;必须写print。 If语句 Input语句&#xff0c;返回的是字符串 len()&#xff0c;长度 小练习&#xff1a; 输入一个自己的生日月份 写个if 和else 判断一下当月是否是你的生日…

celery----异步发送短信

1.目录结构 -celery.py --------必须叫这个名字 放定时任务、里面实例化得到app对象 -home_task.py和user_task.py. ----------就是针对不同app的任务文件 2.各文件的内容 celery.py from datetime import timedeltafrom celery import Celery from celery.schedu…

PLL设计-仿真

线性相位裕锁相环模型 out都代表噪声&#xff0c;PFDCP的gain是Icp/2π&#xff0c;LF的传输函数是,VCO传输函数是,分频器增益是1/N 首先不考虑噪声模型 阶跃响应-查看建立时间&#xff0c;下面两条线是上面两条线减1V后的结果&#xff0c;方便查看。 放大上图&#xff0c;输入…