天天看点

NIO源码解析-IO简述前言:1.同步异步、阻塞非阻塞状态2.操作系统视角下的BIO、NIO和AIO

前言:

    NIO,是一个比较高级的知识点。平时的代码开发中,我们一般很少直接使用NIO相关知识点。但是,其却是各种通信框架的基础知识。如Netty、Mina等,就是基于NIO来进行开发的。

    IO,我们知道,是Input/Output,输入输出,可以是网络流的IO,也可以是文件的IO。通常这是一种BIO。

    到这里,我们引入了BIO、NIO,如果了解的多一点的话还有AIO。那么它们之间有什么关系呢?

    本文将简单介绍上述三者之间的区别,并且拆分NIO的知识点,后续博客会对NIO的各个知识点进行更详细的说明。

1.同步异步、阻塞非阻塞状态

1.1 同步与异步

    经常会听到同步请求,异步请求。

    区分一个请求是同步还是异步的话,主要看请求在调用过来时候,是等待直到执行结果完成,还是及时返回结果,后续通过异步通知或回调的方式来告诉调用方。

    同步请求:调用方发起调用后,会一直等待,直到被调用方返回一个响应结果为止

    异步请求:调用方发起调用后,被调用方立即返回一个响应,后续被调用方通过异步通知或者回调的方式来告知调用方其结果。

1.2 阻塞与非阻塞

    阻塞与非阻塞主要是关注程序在等待执行结果时的状态

    阻塞:当结果返回之前,线程会被挂起(BLOCK状态)

    非阻塞:当结果返回之前,线程不会被挂起(非BLOCK状态)

有了上述基础知识后,我们再来分析下BIO NIO 与AIO的不同之处。

2.操作系统视角下的BIO、NIO和AIO

2.1 BIO

    即Blocking IO(阻塞IO),操作系统下BIO整个过程如下所示:

NIO源码解析-IO简述前言:1.同步异步、阻塞非阻塞状态2.操作系统视角下的BIO、NIO和AIO

    当应用程序发起系统调用时,1)操作系统首先需要先将数据拷贝到系统内核缓冲区,2)然后再将内核缓冲区的数据拷贝到应用程序的进程空间(JVM就是堆内存等)

    在BIO的情况下,应用程序发起系统调用后,会一直等待操作系统执行完上述的数据拷贝之后,才结束调用。(此时该请求线程会被BLOCK)

2.2 NIO

    即None-Blocking IO,操作系统视图下NIO调用过程如下:

NIO源码解析-IO简述前言:1.同步异步、阻塞非阻塞状态2.操作系统视角下的BIO、NIO和AIO

    相比较BIO而言,发起系统调用后,应用程序线程不是一直在阻塞等待数据返回,而是在不停的轮询查询操作系统是否将数据准备好,当操作系统准备好数据之后,后续的从内核空间拷贝数据到用户空间的过程与BIO相同。 

    所以,BIO是上述两个阶段都是阻塞的,而NIO第一个阶段非阻塞,第二个阶段阻塞。

    另:有关于非阻塞IO,还有一个非常重要的概念,叫做多路复用模型。该模型共包含三种解决方案:select、poll、epoll。应用程序使用这些IO函数同时监听多个IO通道的状态变更,可以更好的支持更大量级的连接。

    有关于多路复用模型,会在下一篇文章中单独说明。

2.3 AIO

    即Asynchronous IO,异步IO在操作系统视角下的调用过程如下:

NIO源码解析-IO简述前言:1.同步异步、阻塞非阻塞状态2.操作系统视角下的BIO、NIO和AIO

    应用程序线程发起一个系统调用后,会立即返回,调用事件注册到操作系统上,操作系统准备完成数据并将数据拷贝到用户空间后,会通知应用程序数据已经可用。

    在上述两个过程中,AIO均为非阻塞状态

需要说明的是:Java中的BIO NIO和AIO是java对操作系统的各种IO模型的封装。

IO类型 一阶段(数据拷贝至操作系统内核空间) 二阶段(内核空间数据拷贝至应用程序)
BIO 同步阻塞 同步阻塞
NIO 同步非阻塞 同步阻塞
AIO 异步非阻塞 异步非阻塞

总结:

    实际写一个完整的系列还是蛮困难的,无论写的多还是写的少都比较困难,笔者没有采取先写一个完整示例然后再将示例的知识点拆分的方式,而是反其道而行,先讲解拆分后的知识点,然后最终用一个真实的示例来将知识点串起来。

    整个NIO系列本质上也是其他系列的基础篇章,后续还会有Mycat系列、Netty系列等等。这些高级中间件其实底层也是使用的NIO相关知识。

    工欲善其事必先利其器,让我们一起遨游在NIO的海洋里吧。