1. 同步 I/O
-
定义:I/O 操作按顺序执行,程序会等待当前 I/O 操作完成后再继续执行。
-
特点:
- 简单易理解,适合简单的应用场景。
- 可能导致程序等待,从而降低效率。
2. 异步 I/O
-
定义:I/O 操作不会阻塞程序,程序可以在等待 I/O 操作完成的同时执行其他任务。
-
特点:
- 提高了程序的并发性能。
- 复杂性较高,需要处理回调或事件通知。
3. 阻塞 I/O
-
定义:调用会阻塞程序,直到 I/O 操作完成。
-
特点:
- 操作简单,常用于传统应用。
- 可能导致资源浪费,因为程序在等待时无法执行其他任务。
4. 非阻塞 I/O
-
定义:调用不会阻塞程序,如果不能立即完成,操作会返回错误或特殊值。
-
特点:
- 程序可以继续执行其他任务,提高了资源利用率。
- 需要轮询或使用回调来检查 I/O 状态。
5. 文件 I/O
-
定义:涉及文件的读写操作。
-
特点:
- 常用于数据存储和读取。
- 可能受限于磁盘速度和文件系统性能。
6. 网络 I/O
-
定义:涉及网络通信的 I/O 操作,如发送和接收数据包。
-
特点:
- 常用于客户端-服务器通信。
- 受网络带宽和延迟影响。
7. 内存映射 I/O
-
定义:使用内存映射文件进行 I/O 操作,将文件的一部分映射到内存地址空间。
-
特点:
- 提高了文件读写的效率。
- 适合处理大文件或需要频繁访问的数据。
8. 字符 I/O 和块 I/O
-
字符 I/O:
- 逐字符地进行输入输出。
- 适合处理文本数据。
- 速度较慢,因为每次操作处理一个字符。
-
块 I/O:
- 以数据块为单位进行输入输出。
- 适合处理大量数据。
- 提高了吞吐量,适合磁盘和网络传输。
选择合适的 I/O 模型
- 应用场景:根据应用需求选择合适的 I/O 模型。例如,Web 服务器通常使用异步或非阻塞 I/O 以提高并发性能。
- 性能考虑:需要权衡 I/O 模型的复杂性和性能收益。
- 资源限制:考虑系统资源,如内存和 CPU,以选择合适的 I/O 模型。
阻塞I/O
在 Java 中,阻塞 I/O 是指在 I/O 操作完成之前,线程会被阻塞,无法执行其他任务。以下是 Java 中常见的阻塞 I/O 类型:
1. 文件 I/O
FileInputStream
/FileOutputStream
:用于读取和写入文件的字节流。FileReader
/FileWriter
:用于读取和写入文件的字符流。
2. 网络 I/O
Socket
:用于 TCP 网络通信。accept()
、read()
和write()
方法在等待连接或数据时会阻塞。ServerSocket
:用于监听传入的 TCP 连接,accept()
方法会阻塞直到有连接到达。
3. 标准输入输出
System.in
:读取控制台输入时会阻塞,直到用户输入数据。System.out
:通常用于输出数据到控制台,虽然它本身不阻塞,但等待用户处理输出可能会导致程序等待。
4. NIO(New I/O)中的阻塞模式
FileChannel
和SocketChannel
:在默认情况下是阻塞的,尽管 NIO 提供了非阻塞的能力,但如果不特别设置为非阻塞模式,它们仍然是阻塞的。
示例
以下是一个简单的阻塞网络 I/O 示例:
import java.io.*;
import java.net.*;
public class BlockingIOSocketExample {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8080)) {
System.out.println("Server is listening on port 8080");
// 阻塞等待连接
Socket socket = serverSocket.accept();
System.out.println("Client connected");
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
String message;
// 阻塞读取客户端消息
while ((message = input.readLine()) != null) {
System.out.println("Received: " + message);
output.println("Echo: " + message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
总结
阻塞 I/O 简单易用,但在需要处理大量并发请求时可能导致性能瓶颈。这时可以考虑使用 Java NIO 的非阻塞模式或使用异步 I/O(如 AsynchronousSocketChannel
)来提高性能。