博客
关于我
同步、异步、阻塞、非阻塞、BIO、NIO、AIO
阅读量:728 次
发布时间:2019-03-21

本文共 2868 字,大约阅读时间需要 9 分钟。

网络之间传输数据,可以使用ByteArrayOutputStream类来接收数据,从而避免数据溢出

定义:A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;同步I/O操作导致请求进程被阻塞,直到该I/O操作完成;An asynchronous I/O operation does not cause the requesting process to be blocked;异步I/O操作不会导致请求进程被阻塞;首先阻塞、非阻塞:blocking IO会一直block住对应的进程直到操作完成,而non-blocking IO在kernel还准备数据的情况下会立刻返回。就比如BIO在等待数据阶段,不管数据有没有准备好,都会阻塞;而NIO、IO多路复用在等待数据阶段时,如果数据没有准备好,则会直接返回,不会阻塞。其次同步、异步:根据上面的定义,同步IO将导致进程被阻塞,异步IO不会导致进程阻塞。就比如BIO、NIO、IO多路复用在接收数据阶段,还是会导致进程阻塞,直到数据接收完毕;而AIO在接收数据阶段,是不会导致进程阻塞的。
应用场景:	1. BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。如之前在Apache中使用。	2. NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。如在 Nginx,Netty中使用。	3. AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
多路复用:就是一个线程处理多个请求。优点:之前是一个线程处理一个请求,使用了多路复用,减少了线程的创建和销毁的开销,也避免了线程切换的开销。缺点:当有大量的请求进来时,会导致线程长期阻塞,造成性能瓶颈。

总结:IO 操作都会涉及到操作系统的内核空间和用户空间的转换。IO 操作经常需要与磁盘就行交互,所以IO 操作相比于 CPU 的速度要慢好几个数量级。利用这两者之间的速度差异,就可以实现不同种类的 IO 方式,也就是俗称的 IO 模型。其实 IO 操作就是将数据在用户空间与内核空间进行相互转换,这个过程是通过系统调用来完成的。 IO 技术的发展目标就是如何使用尽可能少的资源来完成数据的传输,这里资源主要就是指 CPU 资源。由于 CPU 比 IO 速度快,而线程的执行又需要 CPU 资源,因此 CPU 就要等待数据就绪和数据传输(ps:数据传输是将数据从内核空间复制到用户空间)这两阶段,着实浪费了CPU的利用率。BIO:BIO 是最经典的一种 IO 方式,也是最简单粗暴的方式,在发起 IO 操作之后,当前调用线程就会处在阻塞状态,直到数据传输完成。NIO:NIO 是在 BIO 基础之上的一个改进,NIO 在数据还未准备好的情况下,不会阻塞进程,而是通过轮询的方式,不断的去查询数据时候准备好,当数据可以被读取时,当前线程就会处在阻塞状态,直到数据读取完成。所以 NIO 中的非阻塞指的是在等待数据的阶段,实际进行数据传输时,还是阻塞的,这点需要注意。IO 多路复用:IO 多路复用是对 NIO 的一个改进,在 NIO 中,需要不断轮询查看数据是否准备好,IO 多路复用的改进是不再主动去查询数据状态是否准备完成,而是等数据准备好的通知,当数据准备完成之后,才会开始传输数据。与 NIO 一样,在数据的传输阶段,当前线程依然是阻塞的。AIO:上面的这些 IO 模型虽然有些号称是不阻塞的,那是指在等待数据就绪的过程中是不阻塞的,但是在接收数据的时候,依然还是阻塞的。AIO 是这些 IO 模型中真正实现完全不阻塞,AIO 在被调用之后直接返回,连接收数据的阶段也是非阻塞的,等到数据接收完成之后,内核才会返回一个通知,也就是说当用户进程接收到通知时,数据已经接收完成。

在这里插入图片描述

这里是具体描述:bio:1、从Java启动IO读的read系统调用开始,用户线程就进入阻塞状态。2、当系统内核收到read系统调用,就开始准备数据。一开始,数据可能还没有到达内核缓冲区(例如,还没有收到一个完整的socket数据包),这个时候内核就要等待。3、内核一直等到完整的数据到达,就会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存),然后内核返回结果(例如返回复制到用户缓冲区中的字节数)。4、直到内核返回后,用户线程才会解除阻塞的状态,重新运行起来。nio:1、在内核数据没有准备好的阶段,用户线程发起IO请求时,立即返回。所以,为了读取到最终的数据,用户线程需要不断地发起IO系统调用。2、内核数据到达后,用户线程发起系统调用,用户线程阻塞。内核开始复制数据,它会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存),然后内核返回结果(例如返回复制到的用户缓冲区的字节数)。3、用户线程读到数据后,才会解除阻塞状态,重新运行起来。也就是说,用户进程需要经过多次的尝试,才能保证最终真正读到数据,而后继续执行。io多路复用:1、选择器注册。在这种模式中,首先,将需要read操作的目标socket网络连接,提前注册到select/epoll选择器中,Java中对应的选择器类是Selector类。然后,才可以开启整个IO多路复用模型的轮询流程。2、就绪状态的轮询。通过选择器的查询方法,查询注册过的所有socket连接的就绪状态。通过查询的系统调用,内核会返回一个就绪的socket列表。当任何一个注册过的socket中的数据准备好了,内核缓冲区有数据(就绪)了,内核就将该socket加入到就绪的列表中。3、用户线程获得了就绪状态的列表后,根据其中的socket连接,发起read系统调用,用户线程阻塞。内核开始复制数据,将数据从内核缓冲区复制到用户缓冲区。4、复制完成后,内核返回结果,用户线程才会解除阻塞的状态,用户线程读取到了数据,继续执行。IO多路复用本质上和非阻塞IO本质上一样,不过利用了新的select系统调用,由内核来负责本来是请求进程该自己做的轮询操作。看似比非阻塞IO还多了一个系统调用开销,不过因为可以支持多路IO,才算提高了效率。aio:1、当用户线程发起了read系统调用,立刻就可以开始去做其他的事,用户线程不阻塞。2、内核就开始了IO的第一个阶段:准备数据。等到数据准备好了,内核就会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存)。3、内核会给用户线程发送一个信号(Signal),或者回调用户线程注册的回调接口,告诉用户线程read操作完成了。4、用户线程读取用户缓冲区的数据,完成后续的业务操作。

转载地址:http://wosgz.baihongyu.com/

你可能感兴趣的文章
MTD技术介绍
查看>>
MySQL
查看>>
MySQL
查看>>
mysql
查看>>
MTK Android 如何获取系统权限
查看>>
MySQL - 4种基本索引、聚簇索引和非聚索引、索引失效情况、SQL 优化
查看>>
MySQL - ERROR 1406
查看>>
mysql - 视图
查看>>
MySQL - 解读MySQL事务与锁机制
查看>>
MTTR、MTBF、MTTF的大白话理解
查看>>
mt_rand
查看>>
mysql -存储过程
查看>>
mysql /*! 50100 ... */ 条件编译
查看>>
mudbox卸载/完美解决安装失败/如何彻底卸载清除干净mudbox各种残留注册表和文件的方法...
查看>>
mysql 1264_关于mysql 出现 1264 Out of range value for column 错误的解决办法
查看>>
mysql 1593_Linux高可用(HA)之MySQL主从复制中出现1593错误码的低级错误
查看>>
mysql 5.6 修改端口_mysql5.6.24怎么修改端口号
查看>>
MySQL 8.0 恢复孤立文件每表ibd文件
查看>>
MySQL 8.0开始Group by不再排序
查看>>
mysql ansi nulls_SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON 什么意思
查看>>