文章目录
1.9 Java网络编程模型
1.9.1 阻塞I/O模型
在阻塞I/O模型中,用户线程发起 read 调用后阻塞等待内核响应。内核等待数据就绪(数据在网络中传输到网卡并被复制到内核空间)之后,把数据从内核空间拷贝到用户空间,再返回成功标识。
1.9.2 非阻塞I/O模型
在非阻塞I/O模型中,用户线程发起 read 调用后不断轮询内核。内核等待数据就绪,在等待数据就绪期间每次轮询都返回一个错误标识,数据就绪之后把数据从内核空间拷贝到用户空间,再返回成功标识。
1.9.3 多路复用I/O模型
在多路复用I/O模型中,使用一个线程的selector来管理多个线程的socket channel。selector监听每个socket channel的状态并且获取文件描述符,再发起 select 调用。内核等待数据就绪,只要有部分数据就绪就把这部分数据所对应的文件描述符事件修改为可读。然后selector通知这部分线程进行read调用读取数据,把数据从内核空间拷贝到用户空间。整个过程中,多个用户线程复用了同一个线程来进行I/O操作,实现并发执行。
为什么 Redis 中要使用 I/O 多路复用这种技术呢?因为 Redis 是跑在「单线程」中的,所有的操作都是按照顺序线性执行的,但是「由于读写操作等待用户输入 或 输出都是阻塞的」,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导,致整个进程无法对其它客户提供服务。而 I/O 多路复用就是为了解决这个问题而出现的。「为了让单线程(进程)的服务端应用同时处理多个客户端的事件,Redis 采用了 IO 多路复用机制。」
这里**“多路”「指的是多个网络连接客户端,」“复用”**指的是复用同一个线程(单进程)。I/O 多路复用其实是使用一个线程来检查多个 Socket 的就绪状态,在单个线程中通过记录跟踪每一个 socket(I/O流)的状态来管理处理多个 I/O 流。
1.9.4 信号驱动I/O模型
在信号驱动IO模型中,用户线程调用一个信号函数来通知内核准备数据,然后继续往下执行。内核在等待数据就绪之后,会向用户线程发送一个信号通知,通知用户线程发起read调用读取数据,把数据从内核空间拷贝到用户空间。
1.9.5 异步I/O模型
在异步IO模型中,用户发起read调用后继续往下执行。内核在等待数据就绪之后把数据从内核空间拷贝到用户空间,然后向用户线程发送一个成功信。
1.9.6 java.io
阻塞I/O模型;面向流;单向;在单线程中,只有完成上一次IO操作才能进行下一次IO操作。
java.io:Serializable、File、InputStream、OutputStream、Reader、Writer。
1.9.7 java.nio
多路复用I/O模型;面向缓冲区;双向;在单线程中,多次IO操作在各个IO通道中并发进行。
java.nio:Selector、Channel、Buffer。
socket client、socket buffer、socket channel、selector