同步阻塞io、同步非阻塞io、异步阻塞io和异步非阻塞io详解和区别

一、同步阻塞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();
        }
    }

}

 

  • 68
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值