JAVA IO、BIO、NIO、AIO及零拷贝
概述
IO,常写作 I/O,是 Input/Output
的简称,是 Input/Output 的简称,即输入/输出。通常指数据在内部存储器(内存)和外部存储器(硬盘、优盘等)或其他周边设备之间的输入和输出。
目前有三种 IO 共存。分别是 BIO、NIO 和 AIO。
BIO 全称 Block-IO
是一种同步且阻塞的通信模式。是一个比较传统的通信方式,模式简单,使用方便。但并发处理能力低,通信耗时,依赖网速。
Java NIO,全程 Non-Block IO
,是 Java SE 1.4 版以后,针对网络传输效能优化的新功能。是一种非阻塞同步的通信模式
Java AIO,全称 Asynchronous IO
,是异步非阻塞的 IO。是一种非阻塞异步的通信模式。在 NIO 的基础上引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。
IO 基本模型
IO的类型主要分为:BIO、NIO 和 AIO,其基本模型如下
阻塞 IO 模型
阻塞 IO 模型,最传统的一种 IO 模型,即在读写数据过程中会发生阻塞现象
。
- 当用户线程发出 IO 请求之后,内核会去查看数据是否就绪,
- 如果
没有就绪
就会等待数据就绪,而用户线程就会处于阻塞状态,用 户线程交出 CPU。 - 当
数据就绪
之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用 户线程才解除 block 状态。
- 如果
典型的阻塞 IO 模型的例子为:如果数据没有就 绪,就会一直阻塞在 read 方法
data = socket.read();
非阻塞 IO 模型
非阻塞 IO 模型:当用户线程发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果
。
- 如果结果是一个 error 时,它就知道数据还没有准备好,于是它可以再次发送 read 操作。
- 一旦内核中的数据准备 好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。
- 所以事实上,
在非阻塞 IO 模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞 IO 不会交出 CPU,而会一直占用 CPU
。
典型的非阻塞 IO 模型一般如下: while 循环中需要不断地去询问内核数据是否就 绪,这样会导致 CPU 占用率非常高,因此一般情况下很少使用 while 循环这种方式来读取数据。
while(true){data = socket.read();if(data!= error){// 处理数据break;}
}
信号驱动 IO 模型
在信号驱动 IO 模型中,
- 当用户线程发起一个 IO 请求操作,会给对应的 socket 注册一个信号函数,然后用户线程会继续执行,
- 当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用 IO 读写操作来进行实际的 IO 请求操作。
异步 IO 模型
异步 IO 模型才是最理想的 IO 模型
在异步 IO 模型中,
当用户线程发起 read 操作之后,立刻就可以开始去做其它的事
。
从内核的角度,
- 当它收到一个 asynchronous read 之后, 它会立刻返回,说明 read 请求已经成功发起了,因此不会对用户线程产生任何 block
- 内核会等待数据准备完成,然后将数据拷贝到用户线程,
- 当这一切都完成之后,内核会给用户线程 发送一个信号,告诉它 read 操作完成了
用户线程完全不需要实际的整个 IO 操作是如何进行的,只需要先发起一个请求
,当接收内核返回的成功信号时表示 IO 操作已经完成,可以直接 去使用数据了
在异步 IO 模型中,IO 操作的两个阶段都不会阻塞用户线程
,这两个阶段都是由内核自动完 成,然后发送一个信号告知用户线程操作已完成
- 在
信号驱动模型中
,当用户线程接收到信号表示数据 已经就绪,然后需要用户线程调用 IO 函数进行实际的读写操作 - 而在
异步 IO 模型中
,收到信号 表示 IO 操作已经完成,不需要再在用户线程中调用 IO 函数进行实际的读写操作。
注意:异步 IO 是需要操作系统的底层支持,在 Java 7 中,提供了 Asynchronous IO
BIO(Blocking I/O)
概述
以前大多数网络通信方式都是阻塞模式的,
- 客户端向服务器端发出请求后,客户端会一直等待(不会再做其他事情),直到服务器端返回结果或者网络出现问题。
- 服务器端同样的,当在处理某个客户端A发来的请求时,另一个客户端B发来的请求会等待,直到服务器端的这个处理线程完成上一个处理。
特点
- 同步阻塞:线程在读写数据时被阻塞,直到操作完成。
- 一连接一线程:每个客户端连接需独立线程处理,高并发时资源消耗大。
缺点:线程数随连接数线性增长,易导致资源耗尽(如 C10K 问题)。
关键类/接口
核心包:java.io
同步阻塞模型,所有操作会阻塞线程直到完成。
适用场景:简单文件操作、低并发网络通信。
类别 | 类/接口 | 用途 |
---|---|---|
字节流 | InputStream/OutputStream | 字节数据的读写(如文件、网络流)。 |
字符流 | Reader/Writer | 字符数据的读写(支持编码转换)。 |
文件操作 | FileInputStream/FileOutputStream | 文件读写。 |
网络通信 | Socket/ServerSocket | TCP 客户端和服务端的阻塞式通信。 |
缓冲流 | BufferedReader/BufferedWriter | 提升 I/O 性能的缓冲包装类。 |
示例
(TCP 服务端)
// 传统 BIO 模型
ServerSocket serverSocket = new ServerSocket(8080);
while (true) {Socket socket = serverSocket.accept(); // 阻塞等待连接new Thread(() -> {try {BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));String request = in.readLine(); // 阻塞读取数据System.out.println("Received: " +</