【JAVA基础】- 同步非阻塞模式NIO详解

【JAVA基础】- 同步非阻塞模式NIO详解

文章目录

  • 【JAVA基础】- 同步非阻塞模式NIO详解
    • 一、概述
    • 二、常用概念
    • 三、NIO的实现原理
    • 四、NIO代码实现
        • 客户端实现
        • 服务端实现
    • 五、同步非阻塞NIO总结

一、概述

NIO(Non-Blocking IO)是同步非阻塞方式来处理IO数据。服务器实现模式为一个请求一个线程,即客户端发送的链接请求都会注册到选择器上,选择器轮询到连接有IO请求时才启动一个线程进行处理。

二、常用概念

  • 同步(synchronous):调用方式指应用(Application),调用方发起有一个功能调用时,在没有得到功能的结果之前,该调用不会返回。也就是说调用方会一直等待被调用方返回功能的结果。
  • 异步(asynchronous):调用方发起一个功能调用时,没有得到功能的结果立即返回,后续被调用方再通过回调等手段,把功能的结构通知调用方。也就是调用方立即得到返回,但是返回中不包含执行的结果。

同步和异步强调的是消息通信机制 (synchronous communication/ asynchronous communication)。所谓同步,就是在发出一个"调用"时,在没有得到结果之前,该“调用”就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由“调用者”主动等待这个“调用”的结果。而异步则是相反,"调用"在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在"调用"发出后,"被调用者"通过状态、通知来通知调用者,或通过回调函数处理这个调用

  • 阻塞:线程发起一个调用时, 在调用返回之前, 线程会被阻塞, 在这个状态下会交出当前CPU的使用权而暂停;也就是调用方会等待调用结果, 调用阻塞了调用方的线程, 线程不在运行处理中。
  • 非阻塞:线程发起一个调用时, 调用会立即返回, 避免线程被阻塞。但是, 返回的结果只是被调用方当前状态的值, 实际使用时, 调用方需要轮询, 直到返回结果符合预期(直到数据准备好)。

阻塞和非阻塞 强调的是程序在等待调用结果(消息,返回值)时的状态. 阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。 对于同步调用来说,很多时候当前线程还是激活的状态,只是从逻辑上当前函数没有返回而已,即同步等待时什么都不干,白白占用着资源。

  • 同步阻塞 IO[BIO - BlockingIO]:在此种方式下,用户进程在发起一个 IO 操作以后,必须等待 IO 操作的完成,只有当真正完成了 IO 操作以后,用户进程才能运行。 JAVA传统的 IO 模型属于此种方式。
  • 同步非阻塞 IO[Non-Blocking IO]:在此种方式下,用户进程发起一个 IO 操作以后 边可 返回做其它事情,但是用户进程需要时不时的询问 IO 操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的 CPU 资源浪费。其中目前 JAVA 的 NIO 就属于同步非阻塞 IO 。
  • 异步阻塞 IO[IO Multiplexing]:此种方式下是指应用发起一个 IO 操作以后,不等待内核 IO 操作的完成,等内核完成 IO 操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问 IO 是否完成,那么为什么说是阻塞的呢?因为此时是通过 select 系统调用来完成的,而 select 函数本身的实现方式是阻塞的,而采用 select 函数有个好处就是它可以同时监听多个文件句柄,从而提高系统的并发性!
  • 异步非阻塞 IO[Asynchronous IO]: 在此种模式下,用户进程只需要发起一个 IO 操作然后立即返回,等 IO 操作真正的完成以后,应用程序会得到 IO 操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的 IO 读写操作,因为 真正的 IO读取或者写入操作已经由 内核完成了。目前 Java 中还没有支持此种 IO 模型。

三、NIO的实现原理

在这里插入图片描述

Java的NIO主要由三个核心部分组成:Channel(通道)Buffer(缓冲区)Selector

所有的IO在NIO中都从一个Channel开始,数据可以从Channel读到Buffer中,也可以从Buffer写到Channel中。Channel有好几种类型,其中比较常用的有FileChannelDatagramChannelSocketChannelServerSocketChannel等,这些通道涵盖了UDP和TCP网络IO以及文件IO。

Buffer本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。Java NIO里关键的Buffer实现有CharBufferByteBufferShortBufferIntBufferLongBufferFloatBufferDoubleBuffer。这些Buffer覆盖了你能通过IO发送的基本数据类型,即byteshortintlongfloatdoublechar

Buffer对象包含三个重要的属性,分别是capacitypositionlimit,其中position和limit的含义取决于Buffer处在读模式还是写模式。但不管Buffer处在什么模式,capacity的含义总是一样的。

capacity:作为一个内存块,Buffer有个固定的最大值,就是capacity。Buffer只能写capacity个数据,一旦Buffer满了,需要将其清空才能继续写数据往里写数据。

position:当写数据到Buffer中时,position表示当前的位置。初始的position值为0。当一个数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity–1。当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0。当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

limit:在写模式下,Buffer的limit表示最多能往Buffer里写多少数据,此时limit等于capacity。当切换Buffer到读模式时, limit表示你最多能读到多少数据,此时limit会被设置成写模式下的position值。

Selector允许单线程处理多个 Channel,如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件例如有新连接进来,数据接收等。

四、NIO代码实现

客户端实现

  • 步骤

    1. 创建SocketChannel 通道
    2. 切换异步非阻塞模式configureBlocking(false)
    3. 设置缓冲区大小ByteBuffer.allocate(1024)
    4. 值写入缓冲区 buffer.put(input.getBytes())
    5. 缓冲区中的值写入通道中channel.write()
  • 代码演示

    public static void main(String[] args) throws IOException {//创建通道SocketChannel channel=SocketChannel.open(new InetSocketAddress("127.0.0.1",6001));//切换异步非阻塞模式channel.configureBlocking(false);//设置缓冲去大小ByteBuffer buffer=ByteBuffer.allocate(1024);System.out.println("输入传输值:");//获取键盘输入的值Scanner scanner = new Scanner(System.in);while (scanner.hasNext()){String input=scanner.next();//把获取的值写入缓冲区中buffer.put(input.getBytes());buffer.flip();//把缓冲区中的值写入通道中channel.write(buffer);buffer.clear();}channel.close();}
    

服务端实现

  • 步骤

    1. 创建ServerSocketChannel通道
    2. 切换异步非阻塞模式configureBlocking(false)
    3. 绑定连接
    4. 获取选择器 Selector open = Selector.open()
    5. 将通道注册到选择器,并指定监听接受事件
    6. 轮训式获取选择已准备就绪的事件
    7. 获取当前选择器所有注册的监听事件
    8. 获取准备就绪的事件
    9. 判断是什么事件准备就绪
    10. 接受就绪,获取客户端连接
    11. 设置非阻塞异步模式
    12. 将通道注册到服务器上
  • 代码演示

    public static void main(String[] args) throws IOException {//创建通道ServerSocketChannel channel=ServerSocketChannel.open();//切换到异步非阻塞模式channel.configureBlocking(false);//绑定链接channel.bind(new InetSocketAddress(6001));//获取选择器Selector open = Selector.open();//将通道注册到选择器,并指定监听接受事件channel.register(open, SelectionKey.OP_ACCEPT);//轮训式获取选择已经准备就绪的事件while(open.select() > 0) {//获取当前选择器所有注册的监听事件Iterator<SelectionKey> it = open.selectedKeys().iterator();while(it.hasNext()) {//获取准备就绪的事件SelectionKey sk = it.next();//判断是什么事件准备就绪if(sk.isAcceptable()) {//接受就绪,获取客户端连接SocketChannel sc = channel.accept();//设置非阻塞异步模式sc.configureBlocking(false);//将通道注册到服务器上sc.register(open, SelectionKey.OP_READ);} else if(sk.isReadable()) {//获取当前选择器就绪的通道SocketChannel s =  (SocketChannel) sk.channel();ByteBuffer bb = ByteBuffer.allocate(1024);int len = 0;while((len = s.read(bb)) > 0) {bb.flip();System.out.println(new String(bb.array(),0,len));bb.clear();}}}it.remove();}}
    

五、同步非阻塞NIO总结

同步非阻塞的特点:应用程序的线程需要不断的进行IO系统调用,轮询数据是否已经准备好,如果没有准备好,就继续轮询,直到完成IO系统调用为止。

同步非阻塞IO的特点:每次发起的IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会被阻塞,实时性较好。

同步非阻塞IO的缺点: 不断地轮询内核,这将占用大量的CPU时间,效率低下。

总体来说,在高并发应用场景下,同步非阻塞IO也是不可用的。一般Web服务器不适用这种IO模型。这种IO模型一般很少直接使用,而是在其他IO模型中使用非阻塞IO这一特性。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ChatGPT 指令大全】怎么使用ChatGPT辅助程式开发

目录 写程式 解读程式码 重构程式码 解 bug 写测试 写 Regex 总结 在当今快节奏的数字化世界中&#xff0c;程式开发变得越来越重要和普遍。无论是开发应用程序、网站还是其他软件&#xff0c;程式开发的需求都在不断增长。然而&#xff0c;有时候我们可能会遇到各种问题…

PCL 计算外接圆的半径

目录 一、算法原理1、计算公式2、主要函数3、源码解析二、代码实现三、结果展示四、参考链接本文由CSDN点云侠原创,原文链接。爬虫自重。 一、算法原理 1、计算公式

【毕业项目】自主设计HTTP

博客介绍&#xff1a;运用之前学过的各种知识 自己独立做出一个HTTP服务器 自主设计WEB服务器 背景目标描述技术特点项目定位开发环境WWW介绍 网络协议栈介绍网络协议栈整体网络协议栈细节与http相关的重要协议 HTTP背景知识补充特点uri & url & urn网址url HTTP请求和…

springboot家政服务管理系统java家务保姆资源 jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 springboot家政服务管理系统 系统1权限&#xff1a;管…

C# PDF加盖电子章

winform界面 1.选择加签pdf按钮代码实现 private void button1_Click(object sender, EventArgs e){OpenFileDialog op new OpenFileDialog();op.Filter "PDF文件(*.pdf)|*.pdf";bool flag op.ShowDialog() DialogResult.OK;if (flag){string pdfPath Path.Get…

c语言进阶部分详解(数据在内存中的存储)

大家好&#xff0c;今天要进行梳理的内容是数据在内存中的存储相关内容。 在C语言中&#xff0c;数据在内存中的存储是一个非常重要的概念。了解数据在内存中的存储方式可以帮助我们更好地理解程序的执行过程&#xff0c;优化内存使用&#xff0c;提高程序的性能。 目录 一.数…

《论文阅读13》Efficient Urban-scale Point Clouds Segmentationwith BEV Projection

一、论文 研究领域&#xff1a; 城市级3D语义分割论文&#xff1a;Efficient Urban-scale Point Clouds Segmentationwith BEV Projection论文链接 注&#xff1a; BEV&#xff1a; Birds Eye View BEV投影是指鸟瞰视角(Birds Eye View,简称BEV)的一种从上方观看对象或场景的…

gin和gorm框架安装

理论上只要这两句命令 go get -u gorm.io/gorm go get -u github.com/gin-gonic/gin然而却出现了问题 貌似是代理问题&#xff0c;加上一条命令 go env -w GOPROXYhttps://goproxy.cn,direct 可以成功安装 安装gorm的数据库驱动程序 go get -u gorm.io/driver/mysql

go错误集(持续更新)

1.提示以下报错 Build Error: go build -o c:\Users\Administrator\Desktop__debug_bin2343731882.exe -gcflags all-N -l . go: go.mod file not found in current directory or any parent directory; see ‘go help modules’ (exit status 1) 解决办法&#xff1a; go …

AJAX-笔记(持续更新中)

文章目录 Day1 Ajax入门1.AJAX概念和axios的使用2. 认识URL3.URL的查询参数4.常用的请求方法和数据提交5.HTTP协议-报文6.接口文档7.form-serialize插件8.案例用户登录 Day2 Ajax综合案bootstrap弹框图书管理图片上传更换背景个人信息设置 Day3 AJAX原理XMLHttpRequestPromise封…

机器学习笔记:李宏毅ChatGPT:生成式学习的两种策略

1 策略1 “各个击破”——autoregressive model “各个击破”——一个一个生成出来 2 策略2 &#xff1a; “一次到位”——non-autoregressve model 一步到位&#xff0c;全部生成出来 2.1 non-autoregressive model 如何确定长度&#xff1f; 两种策略 策略1&#xff1a;始…

【1572. 矩阵对角线元素的和】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个正方形矩阵 mat&#xff0c;请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 示例 1&#xff1a; 输入&#xff1a;mat [[1,2,3]…

MATLAB | 绘图复刻(十一) | 截断的含散点及误差棒的分组柱状图

hey大家好久不见&#xff0c;本期带来一篇绘图复刻&#xff0c;居然已经出到第11篇了&#xff0c;不知道有朝一日有没有机会破百&#xff0c;本期绘制的是《PNAS》期刊中pnas.2200057120文章的figure03&#xff0c;文章题目为Intranasal delivery of full-length anti-Nogo-A a…

数据库新闻速递 -- POSTGRESQL 正在蚕食数据库市场 (翻译)

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请加 liuaustin3微信号 &#xff0c;在新加的朋友会分到3群&#xff…

HTML详解连载(1)

HTML详解连载&#xff08;1&#xff09; HTML定义HTML 超文本标记语言标签语法注意拓展 HTML基本骨架解释VS Code 快速生成骨架&#xff1a;标签的关系父子关系&#xff08;嵌套关系&#xff09;兄弟关系&#xff08;并列关系&#xff09; 代码格式注释 标题标签标签名:h1-h6(双…

分布式数据库视角下的存储过程

存储过程很好呀&#xff0c;那些用不好的人就是自己水平烂&#xff0c;不接受反驳&#xff01;我就有过这样念头&#xff0c;但分布式数据库&#xff0c;更倾向少用或不用存储过程。 1 我从C/S时代走来 C/S架构时代的末期最流行开发套件是PowerBuilder和Sybase数据库&#xf…

unity vscode 代码关联 跳转 BUG

一早打开电脑发现代码关联失效了&#xff0c;目测可能跟昨天一些插件更新有关 结论 就这货&#xff0c;开了就没法提示代码关联&#xff0c;估计预览版全是BUG。 另一个坑 同期有个unity插件也是预览版&#xff0c;“非常好使”&#xff0c;当场去世。评论点开有好几个人说用…

【C++面向对象】--- 继承 的奥秘(上篇)

个人主页&#xff1a;平行线也会相交&#x1f4aa; 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【C之路】&#x1f48c; 本专栏旨在记录C的学习路线&#xff0c;望对大家有所帮助&#x1f647;‍ 希望我们一起努力、成长&…

第三篇|金融人数据来源有哪些

数据对于金融行业真的很重要&#xff0c;那么金融人有哪些途径查数据呢&#xff1f; 国内&#xff1a; 1. 国家统计局 这个应该是无论什么行业都使用最频繁的网站&#xff0c;每个月都会固定发上个月资产投资数据 、工业增加值和利润数据等常规数据&#xff0c;其他数据也会…

半关闭、端口复用与IO多路复用

文章目录 半关闭端口复用IO多路复用&#xff08;IO多路转接&#xff09;模型解决措施 sellect缺点 poll应用缺点 epoll应用工作模式 半关闭 使用close(fd);所对应的文件描述符写和读都关闭了。 端口复用 可以解决绑定失败的问题。 IO多路复用&#xff08;IO多路转接&#…