记-更加深刻理解Java IO
Java IO读写原理
- 在Java层面的应用开发离不开输入流 Input 和 输出流 Output 的处理,简称为IO读写
- 用户程序在进行IO读写操作的时候,离不开 read&write 的调用
- 需要注意的是IO读写并不是物理设备和内存之间的相互读写
- 以read系统为代表的输入流,是把数据从内核缓冲区复制到进程缓冲区
- 以write系统为代表的输出流,是把数据从进程缓冲区复制到内核缓冲区
- 内核缓冲区和磁盘之间的数据读写交换,由操作系统内核完成
Q:什么是内核缓冲区?
- 操作系统的内核拥有对应的内核缓冲区
Q:什么是进程缓冲区?
- 每一个进程拥有进程缓冲区
Q:缓冲区存在的目的?
- 减少频繁的系统IO调用,提高性能
java IO读写流程
- 我们通常会使用到这样的代码
// client
OutputStream os = socket.getOutputStream();
os.write("xxx");
// server
InputStream is = socket.getInputStream();
is.read();
- client发起一次请求,os.write输出流,把数据从进程缓冲区复制到内核缓冲区
- server接收请求,is.read把数据从内核缓冲区复制到进程缓冲区
关于同步和异步
- 同步(Synchronization)异步(Synchronization)
- 同步和异步是基于应用程序和操作系统处理IO所采用的方式
- 同步:一旦开始一个“过程”,调用者必须等到“过程”结束返回结果,才能继续后续的行为
- 异步:调用者会立即收到反馈,调用者可以进行后续操作而不会受到影响
- 同步IO :用户空间线程主动发起IO请求,内核空间被动接受
- 异步IO :内核kernel是主动发起IO请求的一方,用户线程是被动接受方
阻塞和非阻塞
- 阻塞(Block)非阻塞(Non-Block)
- 阻塞和非阻塞是进程在访问数据的时候,数据是否处理就绪的一种处理方式
- 阻塞:需要等待数据处理完毕,才能进行后续操作
- 非阻塞:无论数据是否准备好,立即返回一个结果
- 阻塞IO : 用户空间需要等待内核IO操作彻底完成。直到其返回一个结果。
- 非阻塞IO :内核IO操作无论是否完成,会立即反馈给用户一个状态值,用户空间无需等待
IO模型
- 通过对同步、异步、阻塞和非阻塞有了一个初步的认识过后
- 方便我们更加透彻理解IO模型
BIO 即 同步阻塞IO (Block IO)
- 在Linux系统的Java进程中,默认所有的socket都是 blocking IO 即 阻塞IO
- 应用程序从发起IO调用开始直到系统返回,这段时间是阻塞的。返回成功后,应用程序才会去处理后续逻辑
伪异步IO
- 通过设置socket实现non-blocking
- NIO模型中,应用程序开始调用,有以下两种情况
- 在内核缓冲区没有数据的情况下,系统调用会立即返回一个调用失败的信息
- 在内核缓冲区有数据的情况下,是阻塞的,直到IO操作完成,返回成功结果
- 由于存在阻塞的情况,所以又称为伪异步IO
NIO—非阻塞IO
- 了解NIO之前需要明白:什么是多路复用
- 多路复用模型
- 一个进程可以监视多个状态(FD),一旦某个状态就绪,内核发出反馈完成后续操作
- 典型的IO多路复用模型有 Java Selector、epoll
- 基本原理
- 非阻塞IO的实现基于select/epoll系统的调用,单个线程轮询所负责的socket连接
- 当有socket连接的数据到达时,就返回这些都进行读写的连接
AIO (Asynchronous IO)
- 异步AIO,把IO读写操作完全交给操作系统
- 基本流程
- 用户线程通过系统调用,告知kernel内核启动某个IO操作,用户线程返回。
- kernel内核在整个IO操作(包括数据准备,数据复制)完成后,通知用户,用户执行后续操作