Java IO 与 BIO、NIO、AIO 详解

在 Java 中,I/O(输入/输出)操作是与外部系统(如文件、网络等)进行数据交换的基础。Java 提供了多种 I/O 机制,包括传统的阻塞式 I/O(BIO)、非阻塞式 I/O(NIO)和异步 I/O(AIO)。本文将详细探讨这三种 I/O 模型的特点、区别及其适用场景。

1 BIO(Blocking I/O)

BIO 是一种同步阻塞 I/O 模型。在这种模型中,线程在执行 I/O 操作时会被阻塞,直到操作完成。BIO 适用于连接数较少且稳定的场景。

特点

  • 同步阻塞:线程在执行 I/O 操作时被阻塞,无法处理其他任务。
  • 简单易用:API 直观简单,易于理解和使用。
  • 性能较低:每个连接都需要一个单独的线程,适用于连接数较少的场景。

示例代码

java 复制代码
public class BioFileDemo {
    public static void main(String[] args) {
        BioFileDemo demo = new BioFileDemo();
        demo.writeFile();
        demo.readFile();
    }

    // 使用 BIO 写入文件
    public void writeFile() {
        String filename = "logs/itwanger/paicoding.txt";
        try {
            FileWriter fileWriter = new FileWriter(filename);
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

            bufferedWriter.write("学编程就上技术派");
            bufferedWriter.newLine();

            System.out.println("写入完成");
            bufferedWriter.close();
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 使用 BIO 读取文件
    public void readFile() {
        String filename = "logs/itwanger/paicoding.txt";
        try {
            FileReader fileReader = new FileReader(filename);
            BufferedReader bufferedReader = new BufferedReader(fileReader);

            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println("读取的内容: " + line);
            }

            bufferedReader.close();
            fileReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2 NIO(New I/O 或 Non-blocking I/O)

NIO 是一种同步非阻塞 I/O 模型。在这种模型中,线程在等待 I/O 时可以执行其他任务,通过 Selector 监控多个 Channel 上的事件,提高性能和可伸缩性。NIO 适用于高并发场景。

特点

  • 同步非阻塞:线程在等待 I/O 时可执行其他任务。
  • I/O 多路复用 :通过 Selector 监控多个 Channel 上的事件。
  • 性能较高:单个线程可以处理多个连接,适用于高并发场景。

示例代码

java 复制代码
public class NioFileDemo {
    public static void main(String[] args) {
        NioFileDemo demo = new NioFileDemo();
        demo.writeFile();
        demo.readFile();
    }

    // 使用 NIO 写入文件
    public void writeFile() {
        Path path = Paths.get("logs/itwanger/paicoding.txt");
        try {
            FileChannel fileChannel = FileChannel.open(path, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE));

            ByteBuffer buffer = StandardCharsets.UTF_8.encode("学编程就上技术派");
            fileChannel.write(buffer);

            System.out.println("写入完成");
            fileChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 使用 NIO 读取文件
    public void readFile() {
        Path path = Paths.get("logs/itwanger/paicoding.txt");
        try {
            FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            int bytesRead = fileChannel.read(buffer);
            while (bytesRead != -1) {
                buffer.flip();
                System.out.println("读取的内容: " + StandardCharsets.UTF_8.decode(buffer));
                buffer.clear();
                bytesRead = fileChannel.read(buffer);
            }

            fileChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3 AIO(Asynchronous I/O)

AIO 是一种异步非阻塞 I/O 模型。在这种模型中,线程发起 I/O 请求后立即返回,当 I/O 操作完成时通过回调函数通知线程。AIO 进一步提高了并发处理能力,适用于高吞吐量场景。

特点

  • 异步非阻塞:线程发起 I/O 请求后立即返回,通过回调函数处理结果。
  • 高性能:适用于高吞吐量场景,充分利用操作系统参与并发操作。
  • 复杂性较高:编程复杂度较高,需要处理回调函数。

示例代码

java 复制代码
public class AioDemo {
    public static void main(String[] args) {
        AioDemo demo = new AioDemo();
        demo.writeFile();
        demo.readFile();
    }

    // 使用 AsynchronousFileChannel 写入文件
    public void writeFile() {
        Path path = Paths.get("logs/itwanger/paicoding.txt");
        try {
            AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE);

            ByteBuffer buffer = StandardCharsets.UTF_8.encode("学编程就上技术派");
            Future<Integer> result = fileChannel.write(buffer, 0);
            result.get();

            System.out.println("写入完成");
            fileChannel.close();
        } catch (IOException | InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    // 使用 AsynchronousFileChannel 读取文件
    public void readFile() {
        Path path = Paths.get("logs/itwanger/paicoding.txt");
        try {
            AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            fileChannel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                @Override
                public void completed(Integer result, ByteBuffer attachment) {
                    attachment.flip();
                    System.out.println("读取的内容: " + StandardCharsets.UTF_8.decode(attachment));
                    attachment.clear();
                    try {
                        fileChannel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void failed(Throwable exc, ByteBuffer attachment) {
                    System.out.println("读取失败");
                    exc.printStackTrace();
                }
            });

            Thread.sleep(1000);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4 三种 I/O 模型的区别

模型 同步/异步 阻塞/非阻塞 适用场景
BIO 同步 阻塞 连接数较少且稳定的场景
NIO 同步 非阻塞 高并发场景 (即连接数目多且连接比较短的场景)
AIO 异步 非阻塞 高吞吐量场景 (即连接数目多且连接比较长的场景)

5 总结

  • BIO:采用阻塞式 I/O 模型,线程在执行 I/O 操作时被阻塞,无法处理其他任务,适用于连接数较少且稳定的场景。
  • NIO :使用非阻塞 I/O 模型,线程在等待 I/O 时可执行其他任务,通过 Selector 监控多个 Channel 上的事件,提高性能和可伸缩性,适用于高并发场景。
  • AIO:采用异步 I/O 模型,线程发起 I/O 请求后立即返回,当 I/O 操作完成时通过回调函数通知线程,进一步提高了并发处理能力,适用于高吞吐量场景。

理解这三种 I/O 模型的特点和适用场景,有助于在实际开发中选择合适的 I/O 机制,以提高程序的性能和可扩展性。

6 思维导图

7 参考链接

一文彻底解释清楚Java 中的NIO、BIO和AIO

相关推荐
《源码好优多》1 小时前
基于Java Springboot出租车管理网站
java·开发语言·spring boot
清流君1 小时前
【运动规划】移动机器人运动规划与轨迹优化全解析 | 经典算法总结
人工智能·笔记·算法·机器人·自动驾驶·运动规划
余辉zmh2 小时前
【c++篇】:深入c++的set和map容器--掌握提升编程效率的利器
开发语言·c++
ZhaiMou4 小时前
HTML5拖拽API学习 托拽排序和可托拽课程表
前端·javascript·学习·html5
我想回家种地4 小时前
渗透学习之windows基础
学习
求积分不加C5 小时前
Spring Boot中使用AOP和反射机制设计一个的幂等注解(两种持久化模式),简单易懂教程
java·spring boot·后端
枫叶_v5 小时前
【SpringBoot】26 实体映射工具(MapStruct)
java·spring boot·后端
东方巴黎~Sunsiny5 小时前
java-图算法
java·开发语言·算法
小杨 学习日志6 小时前
C高级学习笔记
c语言·笔记·学习