IO:阻塞和非阻塞、同步和异步

news2024/11/26 22:27:31

阻塞和非阻塞

阻塞的时候线程会被挂起

阻塞

当数据还没准备好时,调用了阻塞的方法,则线程会被挂起,会让出CPU时间片,此时是无法处理过来的请求,需要等待其他线程来进行唤醒,该线程才能进行后续操作或者处理其他请求。

非阻塞

意味着,当数据还没准备好的时候,即便我调用了阻塞方法,该线程也不会被挂起,后续的请求也能够被处理。

同步

同步和异步跟串行和并行非常形似。

假设在一个场景下:完成一个大任务需要4个小任务。

同步的做法:需要依次4个步骤,注意这里是依次,也就是说完成这个步骤,需要先完成前置步骤,也就是说下一个步骤是要看上一个步骤的执行结果。

异步的做法:可以同时进行4个步骤,无需等待其他步骤的执行结果。

阻塞和同步的最本质差别在于:

即便是同步,在等待的过程中,线程是不会被挂起,也不需要让出CPU时间片的,

在IO中的体现

网络编程的基本模型是:Client/Server模型

两个进程之间要相互通信,其中服务端需要提供位置信息,让客户端找到自己。服务端提供IP地址和监听的端口。

客户端拿着这些信息去向服务端发起建立连接请求,通过三次握手成功建立连接后,客户端就可以通过socket向服务器发送和接受消息。

BIO

BIO通信模型采用的是典型的:一请求一应答通信模型

采用BIO通信模型的服务端,通常会由一个独立的Acceptor线程负责监听客户端的连接。

他不负责处理请求,他只是起到一个委派工作的作用,当他接收到请求之后,会为每个客户端创建一个新的线程进行链路处理

处理完之后,通过输出流,返回应答给客户端,然后线程被销毁,资源被回收

该模型的最大问题就是缺乏弹性伸缩能力服务端的线程个数和客户端的并发访问数1:1的关系。

由于线程是Java虚拟机非常宝贵的资源,当线程书膨胀之后,系统的性能会随着并发量增加呈正比的趋势下降。

而且会有OOM的风险,当没有内存空间创建线程时,就无法处理客户端请求,最终导致进程宕机或卡死,无法对外提供服务。

最大的问题就是:每当有一个客户端请求接入时,就会创建一个线程来处理请求

为了改进这个一线程一连接模型,后面又演进出通过:

  • 线程池
  • 消息队列

来实现1个或者多个线程处理N个客户端的模型

在这里,无论是线程池和消息队列,都是解决内存空间线程的问题,并没有实质性地改变同步阻塞通信本质问题

所以这种优化版本的BIO也被称为是伪异步

伪异步IO

采用线程池任务队列可以实现一种:伪异步的IO通信

将客户端的请求封装成一个Task(该任务实现java.lang.Runnable接口),投递到消息队列中。

如果通过线程池维护一堆处理线程,去消费队列中的消息。

处理完毕之后,再去通过客户端就可以了,他的资源是可控的,无论客户端的请求量是多少,也不会发生变化,同样这也是他的缺点之一。

建立连接的accpet方法、读取数据的read方法都是阻塞

这就意味着,如果有一方处理请求或者发出请求的比较慢,或者是网络传输比较慢,那么都会影响对方。

当调用OutputStreamwrite方法写输出流的时候,它将会被阻塞,直到所有要发送的字节全部写入完毕,或者发生异常。

在TCP/IP中,当消息的接收方处理缓慢的时候,由于消息滑动窗口的存在,那么它的接收窗口就会变小,就是那个TCP window size

如果这里采用同步阻塞IO,并且write操作被阻塞很久,直到TCP window size 大于0或者发生IO异常了。

那么通信对方返回应答时间过长会引起的级联故障

  • 线程问题:假如所有的可用线程都被故障服务器阻塞,那么后续所有的IO消息都将被队列中排队
  • 队列问题:如果队列采用的是有界队列队列满了之后那么就会无法后续处理请求;如果采用的是无界队列,那么会有OOM风险。

NIO

NIO,官方叫法是new IO,因为它相对于之前出的java.io包是新增的

但是之前老的IO库都是阻塞的,New IO类库目标就是为了让Java支持非阻塞IO,所有更多的人称为Non-Block IO

缓冲区Buffer

Buffer是一个对象,通常是ByteBuffer类型

任何时候操作NIO中的数据,都需要经过缓冲区

NIO库里,所有数据操作是用缓冲区处理的

  • 读取数据时,是直接读到缓冲区中(这里并没有直接读到某个地方,而是都放到缓冲区中)
  • 写入数据时,写入到缓冲区

缓冲区实质上是一个数组,通常是一个字节数组ByteBuffer,自身还需要维护读写位置,可以用指针或者偏移量来实现。

除了ByteBuffer还有其他基本类型缓冲区

  • CharBuffer:字符缓冲区
  • ShortBuffer:短整型缓冲区
  • IntBuffer:整形缓冲区
  • LongBuffer:长整型缓冲区
  • DoubleBuffer:双精度缓冲区

通常是用ByteBuffer

通道Channel

网络数据通过Channel读取和写入

Channel通道和Stream流最大的区别在于:

  • Channel的数据流向是双向
  • Stream的数据流向是单向

这就意味着:使用Channel,可以同时进行读和写,他是全双工模型。(可以联想到HTTP1.1 HTTP2.0 HTTP3.0 ``websocket

多路复用器Selector

Selector是NIO编程的基础

Selector不断轮询注册在其上的Channel

如果某个Channel发生读写事件,就代表这个Channel是就绪状态,会被Selector轮询出来。

然后根据SelectionKey可以获取就绪Channel的集合,进行后续IO操作。

一个Selector可以轮询多个Channel,JDK是基于epoll代替传统的select,所以不受句柄fd的限制

意味着,一个线程负责Selector的轮询千万个客户端

AIO

NIO2.0引入了新的异步通道的概念,并提供了异步文件通道异步套接字通道的实现

  • 通过java.util.concurrent.Future类来表示异步操作的结果
  • 在执行异步操作的时候传入一个java.nio.channels

CompletionHandler接口的实现类作为操作完成的回调

NIO2.0异步socket通道是真正的异步非阻塞IO

  • 同步socket channel:SocketServerChannel
  • 异步socket channel:AsynchronousServerSocketChannel

它不需要通过多路复用器(selector)对注册到里面的通过进行轮询操作,就可以实现异步读写

AIO和NIO最大的区别在于:异步Socket Channel是被动执行对象

  • NIO需要我们把channel注册到selector上进行顺序扫描、轮询
  • AIO则是通过Future类,实现回调方法:completedfailed

4种IO对比

IO模型主要是探讨2个维度:

  • 同步/异步
  • 阻塞/非阻塞

同步/异步的判断标准主要是:Channel的问题

阻塞/非阻塞的判断标准主要是:selector的问题

阻塞的关键点在于:建立连接数据传输

BIO(阻塞)意味着在完成建立连接(accpet)动作之后,才能进行后续操作

NIO(非阻塞)在处理客户端的连接时,可以将对应的channel注册到Selector上,此时我不管他好了没有,我有Selecotr来帮我去扫就绪态的channel,所以他是非阻塞的

异步非阻塞IO

异步非阻塞IO:AIO

有的人也叫JDK1.4推出的NIO为异步非阻塞IO

但是严格来说,它只能被称为是非阻塞IO,并不是真正意义上的异步

前期selector的底层是通过select/poll来实现的,虽然是用epoll替代了select/poll,上层的API没有变化,只是一次NIO的性能优化,仍旧没有改变IO的模型

JDK1.7提供的NIO2.0新增了:异步套接字通道,他才是真正的异步IO。

多路复用器Selector

Selector的核心功能:就是用来轮询注册在它上面的Channel

当发现某个就绪态的Channel,就会找出他的SelectionKey,然后进行后续的IO操作。

前期的时候JDK1.4,selector底层是基于select/poll技术实现

后面优化,使用epoll来代替

伪异步IO

只是在线程层面上进行了一次优化,IO模型并没有改变

通过处理任务Task队列+线程池处理请求的方式来优化资源

解决了BIO的线程和请求:1对1的关系

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

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

相关文章

Javascript的API基本内容(二)

一、事件监听 结合 DOM 使用事件时,需要为 DOM 对象添加事件监听,等待事件发生(触发)时,便立即调用一个函数。 addEventListener 是 DOM 对象专门用来添加事件监听的方法,它的两个参数分别为【事件类型】和…

产业链金融的前世今生

产业链金融脱胎于供应链金融,又不同于供应链金融。二者的区别是, 供应链金融服务于单个环节、单个企业,而产业链金融是以产业链的核心 企业为依托,针对产业链的各个环节,设计个性化、标准化的金融服务产品,…

Appium自动化测试框架是一种较为优雅的使用方式

以操作小米商城下单为例流程是 启动小米商城app, 点击分类,点击小米手机, 点击小米10 至尊版,点击加入购物车,点击确定....原脚本Copyfrom time import sleep from appium import webdriver from selenium.common.exceptions impo…

python有哪些应用方向及其学习方法 资源推荐

目录 python 语言的应用方向 python简介 1.常规软件开发 2.科学计算 3.自动化运维 4.云计算 5.WEB开发 6.网络爬虫 7.大数据分析 8.人工智能 9.python处理图片和视频 【渗透测试相关工具下载】 推荐阅读 python实战文章 渗透测试文章 渗透测试实战专栏 python黑…

Gorm-学习笔记

1 基本使用 2 创建数据 2.1 如何使用Upsert 使用clause.OnConflict处理数据冲突 2.2 如何使用默认值 通过使用default标签为字段定义默认值 3 查询数据 3.1 First与Find 使用First时,需要注意查询不到数据会返回ErrRecordNotFound。 使用Find查询多条数据&#x…

详讲函数.2.

目录 5. 函数的嵌套调用和链式访问 5.1 嵌套调用 5.2 链式访问 小结: 6. 函数的声明和定义 6.1 函数的声明: 6.2 函数的定义: 5. 函数的嵌套调用和链式访问 函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的…

JUC包:CountDownLatch源码+实例讲解

1 缘起 有一次听到同事谈及AQS时,我有很多点懵, 只知道入队和出队,CLH(Craig,Landin and Hagersten)锁,并不了解AQS的应用, 同时结合之前遇到的多线程等待应用场景,发现…

QML 元素布局

定位器:是QtQuick模块中的提供的,有以下三种 Row 行定位器Column 列定位器Grid 网格定位器Flow 流动定位器常用属性: spacing间距 Row (行定位器) 按照行的方排列 //行定位器 Row{spacing: 5//设置间距Rectangle{width: 100he…

[蓝桥杯] 二分与前缀和习题练习

文章目录 一、二分查找习题练习 1、1 数的范围 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 机器人跳跃问题 1、2、1 题目描述 1、2、2 题解关键思路与解答 1、3 四平方和 1、3、1 题目描述 1、3、2 题解关键思路与解答 二、前缀和习题练习 2、1 前缀和 2、1、1 题目描述…

《操作系统》——第二章 进程与线程

目录 2.1.1进程的概念、组成、特征 2.1.2进程的状态与转换、进程的组织 2.1.3进程控制 2.1.4进程通信 2.1.5线程的概念 2.1.6线程的实现方式和多线程模型 2.2.1调度的概念、层次 2.2.2进程调度的时机、切换与过程、方式 2.2.4调度算法的评价指标 2.2.5调度算法(1) 2…

1249 亲戚(并查集)

1249. 亲戚 题目 提交记录 讨论 题解 视频讲解或许你并不知道,你的某个朋友是你的亲戚。 他可能是你的曾祖父的外公的女婿的外甥女的表姐的孙子。 如果能得到完整的家谱,判断两个人是否是亲戚应该是可行的,但如果两个人的最近公共祖…

数据库之高级查询

注意:第一个包含空,第二句不包含空注意:第二句是错的,聚合函数不能出现在where中。注意:相当于,按照分组属性,求出每个组的聚合函数值,所以肯定不能放单个属性有冲突with rollup是最…

MyBatis - 05 - 封装SqlSessionUtil工具类(用于获取SqlSession对象)并测试功能

文章目录1.新建SqlSessionUtils工具类2.编写静态方法3.项目结构及代码项目结构数据库和表pom.xmlParameterMapper接口:User类:ParameterMapper.xmljdbc.propertieslog4j.xml:mybatis-config.xml:ParameterMapperTest测试类:测试结果1.新建Sql…

leetcode打卡-回溯I

77. 组合 leetcode题目链接&#xff1a;https://leetcode.cn/problems/combinations/ leetcode AC记录&#xff1a; 代码如下&#xff1a; public List<List<Integer>> combine(int n, int k) {List<List<Integer>> res new ArrayList<>(16…

操作系统期末复习

操作系统概论 文章目录操作系统概论操作系统的目标&#xff1a;基本特征:主要功能发展操作系统的运行机制时钟管理中断机制&#xff1a;指令程序处理机状态原语&#xff1a;由若干指令组成的程序段&#xff0c;完成特定功能系统数据结构系统调用体系结构进程--资源分配和调度的…

[黑马程序员SSM框架教程] Spring-22 注解开发依赖注入

1.自动装配是基于暴力反射对私有属性进行装配的&#xff0c;所以不需要setter方法。打破了IOC提供对象&#xff0c;我提供入口的思想。现在不用提供入口也能实现。 2. Qualifier必须依赖注解Autowired&#xff0c;当自动装配的接口类型有多个实现类时使用&#xff0c; 3. Autow…

Linux基础命令-du查看文件的大小

文章目录 du 命令介绍 语法格式 基本参数 参考实例 1&#xff09;以人类可读形式显示指定的文件大小 2&#xff09;显示当前目录下所有文件大小 3&#xff09;只显示目录的大小 4&#xff09;显示根下哪个目录文件最大 5&#xff09;显示所有文件的大小 6&#xff0…

layui框架学习(11:徽章)

应用程序有新增内容、未读消息时&#xff0c;会在按钮或菜单中添加红点或带数字的点状或方状图形&#xff0c;用户看到就知道有新内容&#xff0c;如下图所示QQ邮箱的截图&#xff0c;会通过红色圆点或带NEW的方框提醒用户有新内容可以查看。   CSDN用户如果有新消息&#x…

产品经理有必要考个 PMP吗?(含PMP资料)

现在基本上做产品的都有一个PMP证件&#xff0c;从结果导向来说&#xff0c;不对口不会有这么大范围的人来考&#xff0c;但是需要因地制宜&#xff0c;在公司内部里&#xff0c;标准程序并不流畅&#xff0c;产品和项目并不规范&#xff0c;关系错综复杂。 而产品经理的职能又…

【Java学习】初识Java

JavaSEJava初识1. Java简介2.Java环境的安装与配置3. 开发第一个Java程序Java初识 学前疑问&#xff1a;&#xff08;带着疑问去学习&#xff0c;在学习中自行探索答案&#xff09; Java是什么&#xff1f;能做什么&#xff1f;发展前景如何&#xff1f;需要学习哪些内容&…