一、同步阻塞IO(Blocking IO):
同步阻塞IO是最常见的IO模型。在这种模型下,用户进程发起一个IO请求后,必须等待内核将数据准备好并返回给用户进程。在等待期间,用户进程会被阻塞,不能执行其他任务。只有当数据准备好并返回给用户进程后,用户进程才能继续执行。
二、同步非阻塞IO(Non-Blocking IO):
同步非阻塞IO是在同步阻塞IO的基础上,通过设置socket为非阻塞模式实现的。在这种模型下,用户进程发起IO请求后,会立即得到一个响应,但是这个响应可能是一个错误码,表示数据还没有准备好。用户进程可以继续执行其他任务,但是需要不断轮询或询问内核数据是否准备好。当数据准备好后,用户进程可以再次发起IO请求来获取数据。
三、异步非阻塞IO(Asynchronous Non-Blocking IO):
异步非阻塞IO是最高效的IO模型之一。在这种模型下,用户进程发起IO请求后,会立即得到一个响应,并且这个响应不会是一个错误码,而是表示请求已经被接收并开始处理。用户进程可以继续执行其他任务,而不需要关心数据的准备情况。当数据准备好后,内核会通过信号、回调等方式通知用户进程。用户进程在收到通知后,再来获取数据。这种方式避免了用户进程的阻塞和轮询开销,提高了程序的并发性和响应能力。
四、特点及应用场景:
-
同步阻塞 I/O:
- 特点: 在进行 I/O 操作时,应用程序会一直等待操作完成,这会导致应用程序被阻塞。
- 场景: 适用于简单的 I/O 操作,例如本地文件的读写操作。但是在高并发环境下,同步阻塞 I/O 可能会导致性能问题,因为一个阻塞的 I/O 操作会影响其他操作的执行。
-
同步非阻塞 I/O:
- 特点: 应用程序在进行 I/O 操作后可以立即返回,而不必一直等待操作完成。应用程序需要不断地轮询或者查询状态来检查操作是否完成。
- 场景: 适用于需要处理多个 I/O 事件的情况,例如在网络编程中。虽然减少了阻塞等待的时间,但仍然需要不断地轮询状态,可能会消耗较多的 CPU 资源。
-
异步非阻塞 I/O:
- 特点: 应用程序发起 I/O 请求后可以继续执行其他操作,而不必等待操作完成。当操作完成时,系统会通知应用程序。
- 场景: 适用于高并发且需要处理大量 I/O 事件的情况,例如服务器端编程。异步非阻塞 I/O 可以提高系统的并发性能,避免了多线程或多进程中上下文切换的开销。
总的来说,同步阻塞 I/O 简单易用,但可能导致性能问题;同步非阻塞 I/O 可以减少阻塞等待的时间,但需要频繁轮询状态;异步非阻塞 I/O 在高并发环境下表现优秀,但编程复杂度较高。
为什么没有异步阻塞IO?
因为异步和阻塞通常是相对立的概念,异步IO往往是为了避免阻塞而设计的,所以异步阻塞IO并不是一个有效的IO模型。
异步IO指的是应用程序发起IO请求后,不需要等待IO操作完成就可以继续执行后续的操作。而阻塞IO则是指应用程序在进行IO操作时会一直等待操作完成。
在实际情况中,异步IO通常会配合非阻塞IO一起使用。通过使用异步IO,应用程序可以发起IO请求后继续执行其他操作,而不必一直等待IO操作完成。而非阻塞IO则是指应用程序发起IO请求后可以立即返回,而不必等待IO操作完成,但应用程序需要主动地检查IO操作是否完成。
五、示例代码:
同步阻塞 I/O :
import java.io.*;
public class SyncBlockingIO {
public static void main(String[] args) {
// 定义输入文件和输出文件
File inputFile = new File("input.txt");
File outputFile = new File("output.txt");
try (BufferedReader reader = new BufferedReader(new FileReader(inputFile));
BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile))) {
String line;
// 逐行读取输入文件
while ((line = reader.readLine()) != null) {
// 写入输出文件
writer.write(line);
writer.newLine(); // 换行
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
同步非阻塞 I/O :
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class SyncNonBlockingIO {
public static void main(String[] args) {
// 定义输入文件和输出文件
File inputFile = new File("input.txt");
File outputFile = new File("output.txt");
try (RandomAccessFile inputRAF = new RandomAccessFile(inputFile, "r");
RandomAccessFile outputRAF = new RandomAccessFile(outputFile, "w");
FileChannel inputChannel = inputRAF.getChannel();
FileChannel outputChannel = outputRAF.getChannel()) {
// 设置通道为非阻塞模式
inputChannel.configureBlocking(false);
outputChannel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (true) {
int bytesRead = inputChannel.read(buffer); // 从输入通道读取数据到缓冲区
if (bytesRead == -1) {
break; // 文件末尾
}
buffer.flip(); // 准备从缓冲区读取数据
while (buffer.hasRemaining()) {
outputChannel.write(buffer); // 将数据从缓冲区写入输出通道
}
buffer.clear(); // 清空缓冲区以便下一次读取
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
异步非阻塞 I/O :
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class AsyncNonBlockingIO {
public static void main(String[] args) {
// 定义输入文件和输出文件的路径
Path inputPath = Paths.get("input.txt");
Path outputPath = Paths.get("output.txt");
try (AsynchronousFileChannel inputChannel = AsynchronousFileChannel.open(inputPath, StandardOpenOption.READ);
AsynchronousFileChannel outputChannel = AsynchronousFileChannel.open(outputPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
ByteBuffer buffer = ByteBuffer.allocate(1024); // 创建一个缓冲区
Future<Integer> readFuture = inputChannel.read(buffer, 0); // 异步读取数据到缓冲区的未来任务
while (!readFuture.isDone()) {
// 这里可以执行其他任务,而不必等待I/O操作完成
// 当读取完成时,获取结果
int bytesRead = readFuture.get(); // 获取异步读取的字节数
if (bytesRead == -1) {
break; // 文件末尾
}
buffer.flip(); // 准备从缓冲区读取数据
// 异步写入数据
Future<Void> writeFuture = outputChannel.write(buffer, 0); // 异步写入缓冲区数据到输出通道
writeFuture.get(); // 等待写入完成
buffer.clear(); // 清空缓冲区以便下一次读取
// 开始下一次异步读取
readFuture = inputChannel.read(buffer, 0); // 异步读取数据到缓冲区的未来任务
}
} catch (IOException | InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}