admin 管理员组

文章数量: 887021

Java中BIO,NIO,AIO

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

二、NIO
NIO是New I/O的简称,与旧式的基于流的I/O方法相对,从名字看,它表示新的一套Java I/O标 准。它是在Java 1.4中被纳入到JDK中的,并具有以下特性:
1.NIO是基于块(Block)的,它以块为基本单位处理数据 (硬盘上存储的单位也是按Block来存储,这样性能上比基于流的方式要好一些)
2.为所有的原始类型提供(Buffer)缓存支持
3.增加通道(Channel)对象,作为新的原始 I/O 抽象
4.支持锁(我们在平时使用时经常能看到会出现一些.lock的文件,这说明有线程正在使用这把锁,当线程释放锁时,会把这个文件删除掉,这样其他线程才能继续拿到这把锁)和内存映射文件的文件访问接口
5.提供了基于Selector的异步网络I/O

所有的从通道中的读写操作,都要经过Buffer,而通道就是io的抽象,通道的另一端就是操纵的文件。
NIO有一个很大的特点就是:把数据准备好了再通知我
而Channel有点类似于流,一个Channel可以和文件或者网络Socket对应 。

selector是一个选择器,它可以选择某一个Channel,然后做些事情。
一个线程可以对应一个selector,而一个selector可以轮询多个Channel,而每个Channel对应了一个Socket。
与上面一个线程对应一个Socket相比,使用NIO后,一个线程可以轮询多个Socket。
当selector调用select()时,会查看是否有客户端准备好了数据。当没有数据被准备好时,select()会阻塞。平时都说NIO是非阻塞的,但是如果没有数据被准备好还是会有阻塞现象。
当有数据被准备好时,调用完select()后,会返回一个SelectionKey,SelectionKey表示在某个selector上的某个Channel的数据已经被准备好了。
只有在数据准备好时,这个Channel才会被选择。
这样NIO实现了一个线程来监控多个客户端。
总结:

  1. NIO会将数据准备好后,再交由应用进行处理,数据的读取/写入过程依然在应用线程中完成,只是将等待的时间剥离到单独的线程中去。
  2. 节省数据准备时间(因为Selector可以复用)

三、 AIO
AIO的特点:

  1. 读完了再通知我
  2. 不会加快IO,只是在读完后进行通知
  3. 使用回调函数,进行业务处理
    在理解了NIO的基础上,看AIO,区别在于AIO是等读写过程完成后再去调用回调函数。
    NIO是同步非阻塞的
    AIO是异步非阻塞的
    由于NIO的读写过程依然在应用线程里完成,所以对于那些读写过程时间长的,NIO就不太适合。
    而AIO的读写过程完成后才被通知,所以AIO能够胜任那些重量级,读写过程长的任务。

自己对JavaNIO的一个理解:
NIO最大的优点就是非阻塞嘛,而非阻塞是对于客户端而言的,就是调用读/写方法后,是否能立即返回,能立即返回则是非阻塞,不能立即返回则是阻塞。NIO的非阻塞在于如果有数据,则返回给用户;无则直接返回0,永远不会阻塞。
而IO多路复用的Selector,则是服务端对线程资源的优化。以前一个socket请求就得对应一个服务端的线程去处理,极大浪费服务端线程资源,现在用IO多路复用技术,只需要一个线程就能管理多个socket请求,减少了服务端线程使用数量。
BIO里用户最关心“我要读”,NIO里用户最关心”我可以读了”,在AIO模型里用户更需要关注的是“读完了”。

Linux 5种IO模型:

1到4都是同步的,信号驱动为啥是同步的,因为当操作系统准备好数据后,需要用户线程将数据从内核复制到用户空间。
=Mzg3MjA4MTExMw==&mid=2247484746&idx=1&sn=c0a7f9129d780786cabfcac0a8aa6bb7&source=41#wechat_redirect

IO 多路复用是5种I/O模型中的第3种,对各种模型讲个故事,描述下区别:
故事情节为:老李去买火车票,三天后买到一张退票。参演人员(老李,黄牛,售票员,快递员),往返车站耗费1小时。
1.阻塞I/O模型
老李去火车站买票,排队三天买到一张退票。
耗费:在车站吃喝拉撒睡 3天,其他事一件没干。
2.非阻塞I/O模型
老李去火车站买票,隔12小时去火车站问有没有退票,三天后买到一张票。
耗费:往返车站6次,路上6小时,其他时间做了好多事。
3.I/O复用模型
1.select/poll
老李去火车站买票,委托黄牛,然后每隔6小时电话黄牛询问,黄牛三天内买到票,然后老李去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,打电话17次
2.epoll
老李去火车站买票,委托黄牛,黄牛买到后即通知老李去领,然后老李去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,无需打电话
4.信号驱动I/O模型
老李去火车站买票,给售票员留下电话,有票后,售票员电话通知老李,然后老李去火车站交钱领票。
耗费:往返车站2次,路上2小时,免黄牛费100元,无需打电话
5.异步I/O模型
老李去火车站买票,给售票员留下电话,有票后,售票员电话通知老李并快递送票上门。
耗费:往返车站1次,路上1小时,免黄牛费100元,无需打电话
1同2的区别是:自己轮询
2同3的区别是:委托黄牛
3同4的区别是:电话代替黄牛
4同5的区别是:电话通知是自取还是送票上门

参考文章:
.htm
.html

本文标签: Java中BIO NIO AIO