Java中的IO模型(BIO,NIO,AIO)

BIO是什么?

同步阻塞IO,BlockingIO 的缩写(简单理解:一个线程处理一个连接,发起和处理IO请求都是同步的)
BIO就是传统的java.io包,BIO是面向流:从流中一次可以读取一个或多个字节,交互方式是同步阻塞方式。这意味着,
当一条线程执行read()或者write()方法时,这条线程会一直阻塞直到读取到了一些数据或者要写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情。
缺点:

  1. 当客户端多时,会创建大量的处理线程。且每个线程都要占用栈空间和一些CPU时间
  2. 阻塞可能带来频繁的上下文切换,且大部分上下文切换可能是无意义的。 	

优点:

  代码简单,便于维护 		
  一个线程对应一次请求,单个用户体验好

NIO是什么?

NIO是New I/O的简称 与旧式的基于流的I/O方法相对,从名字看,它表示新的一套Java I/O标 准。
很多人将其翻译成No-Blocking IO 既可以说成是“新I/O” ,也可以叫 同步非阻塞IO。
(简单理解:一个线程处理多个连接,发起IO请求是非阻塞的但处理IO请求是同步的)
NIO是java1.4之后引入的java.nio包,这套API由三个主要的部分组成:Channel(通道),Selectors(多路复用器),Buffer(缓冲区),
其主要想解决的是BIO的大并发问题, NIO是面向块: 数据是先被 读/写到buffer中的,根据需要你可以控制读取什么位置的数据。
可以构建多路复用的、同步非阻塞 IO 程序。

优点:

  1. 由一个专门的线程来处理所有的 IO 事件,并负责分发。
  2. 事件驱动机制:事件到的时候触发,而不是同步的去监视事件。
  3. 线程通讯:线程之间通过 wait,notify 等方式通讯。保证每次上下文切换都是有意义的。减少没有意义的线程切换。 	

缺点:

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

缓冲区 Buffer Buffer是一个对象,包含一些要写入或者读出的数据。
在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,也是写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
缓冲区实际上是一个数组,并提供了对数据结构化访问以及维护读写位置等信息。

      具体的缓存区有:ByteBuffe、CharBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。他们继承了相同的抽象类:Buffer。

通道 Channel 我们对数据的读取和写入要通过Channel,它就像水管一样,是一个通道。通道不同于流的地方就是通道是双向的,
可以用于读、写和同时读写操作。
底层的操作系统的通道一般都是全双工的,所以全双工的Channel比流能更好的映射底层操作系统的API。

  Channel主要分两大类:
       SelectableChannel:用户网络读写
       FileChannel:用于文件操作

多路复用器
Selector是Java NIO 编程的基础。
Selector提供选择已经就绪的任务的能力:Selector会不断轮询注册在其上的Channel, 如果某个Channel上面发生读或者写事件,这个Channel就处于就绪状态,会被Selector轮询出来,
然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作。
一个Selector可以同时轮询多个Channel,因为JDK使用了epoll()代替传统的select实现, 所以没有最大连接句柄1024/2048的限制。所以,只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端。

AIO是什么?

Asynchronous IO 异步非阻塞IO AIO是Java1.7之后引入的包,是NIO的升级版本,提供了异步非阻塞的IO操作方式。(简单理解:一个有效请求一个线程,发起和处理IO请求都是异步的)
异步 IO 是基于事件和回调机制实现的,也就是应用只需要发起一个IO操作然后直接返回,不会堵塞在那里,当操作系统处理完成这个io操作,
操作系统会通知相应的线程进行后续的操作
与NIO不同,操作系统负责处理内核区/用户区的内存数据迁移和真正的IO操作,应用程序只须直接调用API的read或write方法即可。
这两种方法均为异步的,对于读操作而言,当有流可读取时, 操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;
对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序
在JDK1.7中,这部分内容被称作NIO.2,主要在java.nio.channels包下增加了下面四个异步通道:
AsynchronousSocketChannel AsynchronousServerSocketChannel
AsynchronousFileChannel AsynchronousDatagramChannel
其中的read/write方法,会返回一个带回调函数的对象,当执行完读取/写入操作后,直接调用回调函数。

同步与异步?阻塞与非阻塞?

一个IO的操作可以分为两个步骤:发起IO请求和实际的IO操作
阻塞与非阻塞的区别在于,第一步发起IO请求时是否会被阻塞,如果一直等到数据到来时(或超时)才返回, 那么就是传统的阻塞IO。
如果是等到数据到来时接收通知,再进行后续的读写操作。那么就是非阻塞IO
同步和异步的区别就在于,第二步实际操作IO时是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO ,如果不阻塞,而是操作系统做完IO两个阶段的操作再将结果返回,那么就是异步IO
使用同步时,由java自己处理IO读写,使用异步时,Java将IO读写委托给OS处理。

NIO和IO到底有什么区别?有什么关系?

BIO是面向流:从流中一次可以读取一个或多个字节,拿到读取的这些做什么你说了算。
这里没有任何缓存(这里指的是使用流没有任何缓存,接收或者发送的数据是缓存到操作系统中的,流就像一根水管从操作系统的缓存中读取数据)而且只能顺序从流中读取数据。
如果需要跳过一些字节或者再读取已经读过的字节,你必须将从流中读取的数据先缓存起来。

NIO是面向块:数据是先被 读/写到buffer中的,根据需要你可以控制读取什么位置的数据。
这在处理的过程中给用户多了一些灵活性,然而,你需要额外做的工作是检查你需要的数据是否已经全部到了buffer中,你还需要保证当有更多的数据进入buffer中时,buffer中未处理的数据不会被覆盖。
在数据处理之前必须要判断缓冲区的数据是否完整或者已经读取完毕。在效率上,NIO效率比IO效率会高出很多。

总结:

NIO不在是和BIO一样用OutputStream和InputStream 输入流的形式来进行处理数据的,但是又是基于这种流的形式,采用了通道和缓冲区的形式来进行处理数据的。
NIO的通道是可以双向的,但是IO中的流只能是单向的。
还有就是NIO的缓冲区(其实也就是一个字节数组)还可以进行分片,可以建立只读缓冲区、直接缓冲区和间接缓冲区,只读缓冲区很明显就是字面意思,直接缓冲区是为加快 I/O 速度,而以一种特殊的方式分配其内存的缓冲区。
在BIO模式下,调用read,如果发现没数据已经到达,就会Block住。
在NIO模式下,调用read,如果发现没数据已经到达,就会立刻返回-1。

NIO给我们带来了些什么:

事件驱动模型
避免多线程
单线程处理多任务
非阻塞I/O,I/O读写不再阻塞,而是返回0
基于block的传输,通常比基于流的传输更高效
更高级的IO函数,zero-copy
IO多路复用大大提高了Java网络应用的可伸缩性和实用性

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

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

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

AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值