1、同步阻塞IO
首先,解释一下阻塞与非阻塞。
阻塞 IO 指的是需要内核 IO 操作彻底完成后才返回到用户空间执行用户程序的操作指令。“阻塞”指的是用户程序(发起IO请求的进程或者线程)的执行状态。可以说传统的 IO 模型都是阻塞 IO 模型,并且在 Java 中默认创建的 socket 都属于阻塞 IO 模型。
其次,解释一下同步与异步。简单来说,可以将同步与异步看成发起 IO 请求的两种方式。同步 IO 是指用户空间(进程或者线程)是主动发起 IO 请求的一方,系统内核是被动接收方。异步 IO 则反过来,系统内核是主动发起 IO 请求的一方,用户空间是被动接收方。
同步阻塞 IO(Blocking IO)指的是用户空间(或者线程)主动发起,需要等待内核 IO 操作彻底完成后才返回到用户空间的 IO 操作。在 IO 操作过程中,发起 IO 请求的用户进程(或者线程)处于阻塞状态。
2、同步非阻塞IO
非阻塞IO(Non-Blocking IO,NIO)指的是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间去执行后续的指令,即发起 IO 请求的用户进程(或者线程)处于非阻塞状态,与此同时,内核会立即返回给用户一个 IO 状态值。
阻塞和非阻塞的区别是什么呢?阻塞是指用户进程(或者线程)一直在等待,而不能做别的事情;非阻塞是指用户进程(或者线程)获得内核返回的状态值就返回自己的空间,可以去做别的事情。
在 Java 中,非阻塞 IO 的 socket 被设置为 NONBLOCK 模式。
同步非阻塞 IO 指的是用户进程主动发起,不需要等待内核IO操作彻底完成就能立即返回用户空间的IO操作。在 IO 操作过程中,发起 IO 请求的用户进程(或者线程)处于非阻塞状态。
同步非阻塞 IO 也可以简称为 NIO,但是它不是 Java 编程中的 NIO。Java 编程中的 NIO(New IO)类库组件所归属的不是基础 IO 模型中的 NIO 模型,而是 IO 多路复用模型。
3、IO多路复用
为了提高性能,操作系统引入了一种新的系统调用,专门用于查询 IO 文件描述符(含 socket 连接)的就绪状态。在 Linux 系统中,新的系统调用为 select/epoll 系统调用。通过该系统调用,一个用户进程(或者线程)可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓冲区可读/可写),内核就能够将文件描述符的就绪状态返回给用户进程(或者线程),用户空间可以根据文件描述符的就绪状态进行相应的 IO 系统调用。
IO 多路复用(IO Multiplexing)属于一种经典的 Reactor 模式实现,有时也称为异步阻塞 IO,Java 中的 Selector 属于这种模型。
4、异步IO
异步 IO(Asynchronous IO,AIO)指的是用户空间的线程变成被动接收者,而内核空间成为主动调用者。在异步 IO 模型中,当用户线程收到通知时,数据已经被内核读取完毕并放在了用户缓冲区内,内核在 IO 完成后通知用户线程直接使用即可。
异步 IO 类似于 Java 中典型的回调模式,用户进程(或者线程)向内核空间注册了各种 IO 事件的回调函数,由内核去主动调用。