BIO、NIO、AIO
<h2>一、概述</h2>
<pre><code>Java 中的 BIO、NIO和 AIO 可以理解为是 Java 语言对操作系统的各种 IO 模型的封装。在使用这些API的时候,不需要关心操作系统层面的知识,也不需要根据不同操作系统编写不同的代码。只需要使用Java的API就可以了。
同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。
异步: 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者并没有返回结果,此时我们可以处理其他的请求,被调用者通常依靠事件,回调等机制来通知调用者其返回结果。
区别: 同步和异步的区别最大在于异步的话调用者不需要等待处理结果,被调用者会通过回调等机制来通知调用者其返回结果。
阻塞: 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
非阻塞: 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。</code></pre>
<h2>二、BIO</h2>
<pre><code>同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。
采用 BIO 通信模型(典型的请求-应答模型) 的服务端,通常由一个独立的 Acceptor 线程负责监听客户端的连接。如果要能够同时处理多个客户端请求,就必须使用多线程。但创建过多的线程如果未有效利用,会造成不必要的开销,可以通过线程池改善。
客户端数M一般大于线程池的最大线程数N,这就伪异步IO。
总结:在活动连接数不是特别高(小于单击1000)的情况下,这种模式还是比较不错,可以让每一个连接专注于自己的I/O并且编程简单,也不用考虑过载、限流等问题。但是连接数过高就不适用了。</code></pre>
<h2>三、NIO</h2>
<pre><code>简介:
NIO是一种同步非阻塞的I/O模型,它支持面向缓冲的,基于通道的I/O操作方法。提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现。 对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。
NIO的特性/NIO与IO区别:
1.IO流是阻塞的,NIO流是不阻塞的。单线程中从通道读取数据到buffer,同时可以继续做别的事情,当数据读取到buffer中后,线程再继续处理数据。写数据也是一样的。另外,非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。Java IO的各种流是阻塞的。这意味着,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。
2.Buffer(缓冲区)。IO 面向流(Stream oriented),而 NIO 面向缓冲区(Buffer oriented)。Buffer是一个对象,它包含一些要写入或者要读出的数据。在面向流的I/O中·可以将数据直接写入或者将数据直接读到 Stream 对象中。虽然 Stream 中也有 Buffer 开头的扩展类,但只是流的包装类,还是从流读到缓冲区,而 NIO 却是直接读到 Buffer 中进行操作。
3.Channel (通道)。NIO 通过Channel(通道) 进行读写。通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。
4.Selector(选择器)。NIO有选择器,而IO没有。选择器用于使用单个线程处理多个通道。因此,它需要较少的线程来处理这些通道。线程之间的切换对于操作系统来说是昂贵的。 因此,为了提高系统效率选择器是有用的。
NIO 读数据和写数据方式:
通常来说NIO中的所有IO都是从 Channel(通道) 开始的。
1.从通道进行数据读取 :创建一个缓冲区,然后请求通道读取数据。
2.从通道进行数据写入 :创建一个缓冲区,填充数据,并要求通道写入数据。
NIO核心组件:
Channel(通道)、Buffer(缓冲区)、Selector(选择器)
由于JDK 原生 NIO 难用,编程复杂,自己实现的NIO又容易出现bug,所以一般都是通过Netty来使用NIO。</code></pre>
<h2>四、AIO</h2>
<pre><code>AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。(除了 AIO 其他的 IO 类型都是同步的)</code></pre>
<h2>五、附注</h2>
<pre><code>Linux系统的五种I/O模型:
1.阻塞IO模型:阻塞 I/O 是最简单的 I/O 模型,一般表现为进程或线程等待某个条件,如果条件不满足,则一直等下去。条件满足,则进行下一步操作。
2.非阻塞IO模型:应用进程与内核交互,目的未达到之前,不再一味的等着,而是直接返回。然后通过轮询的方式,不停的去问内核数据准备有没有准备好。如果某一次轮询发现数据已经准备好了,那就把数据拷贝到用户空间中。
3.信号驱动IO模型:应用进程在读取文件时通知内核,如果某个 socket 的某个事件发生时,请向我发一个信号。在收到信号后,信号对应的处理函数会进行后续处理。
4.IO复用模型:多个进程的IO可以注册到同一个管道上,这个管道会统一和内核进行交互。当管道中的某一个请求需要的数据准备好之后,进程再把对应的数据拷贝到用户空间中。由于没有向内核注册信号处理函数,所以,他并不是非阻塞的。
5.异步IO模型:应用进程把IO请求传给内核后,完全由内核去操作文件拷贝。内核完成相关操作后,会发信号告诉应用进程本次IO已经完成。
除了异步IO模型,其它的都是同步的。</code></pre>