同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO

  IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。

一、BIO

     在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。

二、NIO

    NIO本身是基于事件驱动思想来完成的,其主要想解决的是BIO的大并发问题: 在使用同步I/O的网络应用中,如果要同时处理多个客户端请求,或是在客户端要同时和多个服务器进行通讯,就必须使用多线程来处理。也就是说,将每一个客户端请求分配给一个线程来单独处理。这样做虽然可以达到我们的要求,但同时又会带来另外一个问题。由于每创建一个线程,就要为这个线程分配一定的内存空间(也叫工作存储器),而且操作系统本身也对线程的总数有一定的限制。如果客户端的请求过多,服务端程序可能会因为不堪重负而拒绝客户端的请求,甚至服务器可能会因此而瘫痪。

    NIO基于Reactor,当socket有流可读或可写入socket时,操作系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操作系统。  也就是说,这个时候,已经不是一个连接就要对应一个处理线程了,而是有效的请求,对应一个线程,当连接没有数据时,是没有工作线程来处理的。

   BIO与NIO一个比较重要的不同,是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。

      NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式。

      在NIO的处理方式中,当一个请求来的话,开启线程进行处理,可能会等待后端应用的资源(JDBC连接等),其实这个线程就被阻塞了,当并发上来的话,还是会有BIO一样的问题。

  HTTP/1.1出现后,有了Http长连接,这样除了超时和指明特定关闭的http header外,这个链接是一直打开的状态的,这样在NIO处理中可以进一步的进化,在后端资源中可以实现资源池或者队列,当请求来的话,开启的线程把请求和请求数据传送给后端资源池或者队列里面就返回,并且在全局的地方保持住这个现场(哪个连接的哪个请求等),这样前面的线程还是可以去接受其他的请求,而后端的应用的处理只需要执行队列里面的就可以了,这样请求处理和后端应用是异步的.当后端处理完,到全局地方得到现场,产生响应,这个就实现了异步处理。

三、AIO

     与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。  即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。  在JDK1.7中,这部分内容被称作NIO.2,主要在java.nio.channels包下增加了下面四个异步通道:

  • AsynchronousSocketChannel
  • AsynchronousServerSocketChannel
  • AsynchronousFileChannel
  • AsynchronousDatagramChannel

其中的read/write方法,会返回一个带回调函数的对象,当执行完读取/写入操作后,直接调用回调函数。

BIO是一个连接一个线程。

NIO是一个请求一个线程。

AIO是一个有效请求一个线程。

先来个例子理解一下概念,以银行取款为例: 

  • 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写);
  • 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS(银行卡和密码),OS需要支持异步IO操作API);
  • 阻塞 : ATM排队取款,你只能等待(使用阻塞IO时,Java调用会一直阻塞到读写完成才返回);
  • 非阻塞 : 柜台取款,取个号,然后坐在椅子上做其它事,等号广播会通知你办理,没到号你就不能去,你可以不断问大堂经理排到了没有,大堂经理如果说还没到你就不能去(使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器会通知可读写时再继续进行读写,不断循环直到读写完成)

Java对BIO、NIO、AIO的支持:

  • Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。

  • Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

  • Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,

BIO、NIO、AIO适用场景分析:

  • BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。

  • NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。

  • AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。

另外,I/O属于底层操作,需要操作系统支持,并发也需要操作系统的支持,所以性能方面不同操作系统差异会比较明显。

在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作。

    在比较这两个模式之前,我们首先的搞明白几个概念,什么是阻塞和非阻塞,什么是同步和异步,同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知。而阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值。

 一般来说I/O模型可以分为:同步阻塞,同步非阻塞,异步阻塞,异步非阻塞IO

同步阻塞IO在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。JAVA传统的IO模型属于此种方式!

同步非阻塞IO:在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。

异步阻塞IO此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,那么为什么说是阻塞的呢?因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄,从而提高系统的并发性!

 异步非阻塞IO:在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。目前Java中还没有支持此种IO模型。   

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

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

相关文章

1 概述

Unix C TCP/IP 三位一体 Linux天生是网络操作系统 程序员的学习:不断地敲代码,不断地看别人的代码。 Linux两大领域: (1)服务器 (2)嵌入式设备 www.netcraft.com 查看网站服务器系统 VMware快…

对我影响最大的三位老师

读书也读了那么多年了,遇见了许多的老师,他们教不同的科目,各司其职,兢兢业业的做着自己的本职工作。在我的学生时代印象最深的有三位老师。第一位是我的初中语文老师邹老师,他上课非常有趣,语文课&#xf…

Java Annotation认知(包括框架图、详细介绍、示例说明)

摘要 Java Annotation是JDK5.0引入的一种注释机制。 网上很多关于Java Annotation的文章,看得人眼花缭乱。Java Annotation本来很简单的,结果说的人没说清楚;弄的看的人更加迷糊。 我按照自己的思路,对Annotation进行了整理。理解…

matlab练习程序(RGB2HSL、HSL2RGB)

色相饱和度亮度和三原色的相互转换 function mainimgimread(lena_color.jpg);imgmat2gray(img); %任意区间映射到[0,1];[m n dim]size(img);imshow(img);%%图像的RGBRimg(:,:,1);Gimg(:,:,2);Bimg(:,:,3);%%图像RGB2HSLHzeros(m,n); %色相角Szeros(m,n); %饱和度Lzeros(m,…

2 文件处理、权限管理、搜索

文件处理命令: ls -a -l -d -h -i mkdir -p parents cd . .. /tmp/Japan pwd rmdir cp -r -p source destination 可改名recursive preserve mv source destination 剪切文件 改名 ctrl l 清屏 或者 clear命令 rm -r -f touch 新建文件 带空格需加…

第38节: Vue3 鼠标按钮修改器

在UniApp中使用Vue3框架时&#xff0c;你可以使用按键修饰符来更精确地处理键盘事件。以下是一个示例&#xff0c;演示了如何在UniApp中使用Vue3框架使用.left、.right和.middle按键修饰符&#xff1a; <template> <view> <input keydown"handleKeyDown&…

Go语言学习之3 流程控制、函数

主要内容&#xff1a; 1. strings和strconv使用2. Go中的时间和日期类型3. 指针类型4. 流程控制5. 函数详解 1. strings和strconv使用 //strings 1. strings.HasPrefix(s string, prefix string) bool&#xff1a;判断字符串s是否以prefix开头 。 2. strings.HasSuffix(s strin…

RabbitMQ教程总结

【译】RabbitMQ教程一 主要通过Hello Word对RabbitMQ有初步认识 【译】RabbitMQ教程二 工作队列&#xff0c;即一个生产者对多个消费者循环分发、消息确认、消息持久、公平分发 【译】RabbitMQ教程三 如何同一个消息同时发给多个消费者开始引入RabbitMQ消息模型中的重要概念路由…

3 帮助命令、用户管理、压缩

帮助命令&#xff1a; man 命令或配置文件 获得帮助信息 /l 查看所有和l相关的行 q 退出 man passwd 1命令的帮助 5配置文件的帮助 man 1 passwd man 5 passwd 默认查看命令的帮助 man 5 passwd 查看配置文件的帮助 whatis 命令 查看命令的功能性描述 whatis ls ap…

[bzoj1039] [ZJOI2008]无序运动Movement

Description D博士对物理有着深入的研究&#xff0c;经典物理、天体物理、量子物理都有着以他的名字命名的定理。最近D博士着迷于研究粒子运动的无规则性。对圣经深信不疑的他相信&#xff0c;上帝创造的任何事物必然是有序的、有理可循的&#xff0c;而不是无规则的、混沌的。…

关于shiro session失效报错问题

最近做了一个项目&#xff0c;要用到shiro&#xff0c;做完之后发现有个异常经常发生org.apache.shiro.session.UnknownSessionException: There is no session with id &#xff0c;经过多天的研究&#xff0c;终于得以解决 登录的时候异常信息&#xff1a; [java] view plain…

4 网络、挂载、关机

网络命令: 给在线用户发信 write 用户名 编辑时&#xff0c;Ctrl退格键删除错误输入 CtrlD 保存输入信息 wall 给所有在线用户发信 ping命令 -c指定发送次数 ping -c 3 192.168.231.1 ifconfig 查看网卡信息 ifconfig eth1 192.168.231.100 临时设置IP地址 mail 用户名 …

#191 sea(动态规划)

假设已经求出了i个点j个桥的连通图数量f[i][j]&#xff0c;容易由此推出最终答案&#xff0c;套路地枚举1号点所在连通块大小即可。 假设已经求出了i个点的边双连通图数量h[i]&#xff0c;考虑由此推出f[i][j]。可以枚举其中一座桥将图划分成两个部分&#xff0c;固定1号点在其…

linux下获取占用CPU资源最多的10个进程,可以使用如下命令组合: ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head linux下

linux下获取占用CPU资源最多的10个进程&#xff0c;可以使用如下命令组合&#xff1a; ps aux|head -1;ps aux|grep -v PID|sort -rn -k 3|head linux下获取占用内存资源最多的10个进程&#xff0c;可以使用如下命令组合&#xff1a; ps aux|head -1;ps aux|grep -v PID|s…

自定义注解与validation结合使用案例

案例1&#xff1a; [java] view plaincopy import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import…

5 Vim编辑器的使用

vi filename 命令模式 a i o 插入模式 后前 行 Esc键 回到命令模式 Shift&#xff1a; 编辑模式 set nu加行号 执行完命令后直接回到命令模式 :set nu 设置行号 :set nonu 取消行号 移动命令&#xff1a; gg 到第一行 G 到最后一行 nG 到第n行 :n到第n行 $ 移至行…

机器学习实战(笔记)------------KNN算法

1.KNN算法 KNN算法即K-临近算法&#xff0c;采用测量不同特征值之间的距离的方法进行分类。 以二维情况举例&#xff1a; 假设一条样本含有两个特征。将这两种特征进行数值化&#xff0c;我们就可以假设这两种特种分别为二维坐标系中的横轴和纵轴&#xff0c;将一个样本以点的形…

hive的安装配置

hive只需安装在一个节点上。 1、将安装包解压&#xff0c;cd入conf文件夹下&#xff0c;执行命令cp hive-default.xml hive-site.xml 2、更改hive-site.xml的配置项 </property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql:/…

Java注解Annotation 完成验证

Java注解Annotation用起来很方便&#xff0c;也越来越流行&#xff0c;由于其简单、简练且易于使用等特点&#xff0c;很多开发工具都提供了注解功能&#xff0c;不好的地方就是代码入侵比较严重&#xff0c;所以使用的时候要有一定的选择性。 这篇文章将利用注解&#xff0c;来…

隐藏马尔科夫模型HMM

概率图模型 HMM 先从一个具体的例子入手,看看我们要解决的实际问题.例子引自wiki.https://en.wikipedia.org/wiki/Hidden_Markov_model Consider two friends, Alice and Bob, who live far apart from each other and who talk together daily over the telephone about what …