Java中三种IO模式Bio,Nio,Aio 以及 Tomcat中的 Bio, Nio,Apr模式

概述:

由于项目需要,来来回回看了几篇有关的博客,这里就简要做一下总结分析:
java支持的三种io模式中,分为三种,Bio,Nio,Aio,其中Aio也叫Nio2. Nio是jdk1.4及以后支持的,Aio是jdk7及以后支持的。

Tomacat服务器中也有三种模式,分别为Bio, Nio,Apr模式。和上述的io模式有些类似。

先来整体认识下同步阻塞,同步非阻塞,异步阻塞的概念。

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

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

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

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

以下进行详细介绍:

Tomcat的三种模式:

1.BIO
传统BIO模式主要是这样的一个阻塞IO运行模式。

当一个HTTP请求过来时,服务器立马调用serverSocket.accept()接受一个socket,然后服务器从线程池中取一个线程并且将这个socket传给这个线程处理。

这个线程就会调用读数据流的方法读取socket中携带的数据流,然后将读取的数据流利用http协议解析成httprequest对象,然后将这个对象传给servlet处理。

当servlet处理完毕之后该线程将处理后返回的数据再调用写方法写到客户端。但是这个过程存在一个问题,就是一般的io操作都比较慢。比如线程在读数据的时候,因为io操作比较慢所以要线程要等待io准备好读的数据后才能读取数据,在io准备数据的时候线程一直处于等待浪费状态。

在比如当线程往外写数据的时候,因为io处理比较慢所以线程要等待io把线程写入到数据都输出完毕并且关闭socket后才释放这个线程,在io往外输出的这段时间内线程也处于等待浪费的状态。所以这就是IO操作对线程的阻塞作用。

从上面的过程可以看出因为socket和线程是绑定的,所以有多少个线程那么就只能维持多少个socket连接。这就大大的影响了Tomcat的并发量。

2.NIO
要增加并发量就必须要解决io操作对线程的阻塞作用。这样NIO模式就应用而生了。非阻塞IO

所谓NIO模式就是在IO操作(读或者写)的阻塞线程的时候要把线程释放掉,让线程去处理其他的没有阻塞的socket的io流去。这样就提高了线程的利用率,相同的线程可以处理的socket连接要比BIO模式更多了。

NIO模式创建了Channel和Selector两个概念。

当一个http请求过来的时候,服务器立马将接受到的socket扔给一个Channel,由这个Channel保持和客户端的连接状态。

随后,这个Channel会去selector注册一个连接事件,但是这时候还不会调用线程让线程操作io流。当Channel将所有的数据都写入到自己的buffer中后会向selector注册一个读事件。

服务器的一个线程遍历selector的时候发现有一个读事件才会调用一个线程池中的线程,并且将这个通道传给这个线程让线程去读取缓冲区中已经准备好的数据并且组织解析好数据调用servlet处理数据。

等这个线程将数据返回的时候,会将返回的数据写入到这个Channel的写buffer中去,然后向selector注册一个写事件。这时候不用等待io都把数据输出后才释放线程就可以直接释放线程了。

服务器的一个线程循环selector发现有一个写事件,这时候将buffer中的数据输出到客户端。这样使用同样的线程数相比BIO模式可以大大的增加socket连接数量,并且增加了线程的数据处理效率,最终增加了Tomcat可以承载的并发量。

BIO与NIO一个比较重要的不同,是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程
在这里插入图片描述
NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式。

3.APR模式

apr(Apache portable Run-time libraries/Apache可移植运行库)是Apache HTTP服务器的支持库。异步非阻塞
在apr模式下,Tomcat将以JNI(Java Native Interface)的形式调用Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大提高Tomcat对静态文件的处理性能。Tomcat apr是在Tomcat上运行高并发应用的首选模式。

Java中的三种Io模式:

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

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

Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。详细点的过程:与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。

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

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

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

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

至于后续的代码配置,可以参考一些博客,比如:
https://blog.csdn.net/wanglei_storage/article/details/50225779
还没有亲自尝试,不确定正确性,就先不贴出来了,等后续真正调优尝试后再进行更新。
本文参考的博客:
https://blog.csdn.net/skiof007/article/details/52873421
https://blog.csdn.net/wanglei_storage/article/details/50225779
https://blog.csdn.net/weichi7549/article/details/107772717

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值