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

相关推荐
lsx20240610 分钟前
SQL MID()
开发语言
Dream_Snowar13 分钟前
速通Python 第四节——函数
开发语言·python·算法
西猫雷婶15 分钟前
python学opencv|读取图像(十四)BGR图像和HSV图像通道拆分
开发语言·python·opencv
鸿蒙自习室15 分钟前
鸿蒙UI开发——组件滤镜效果
开发语言·前端·javascript
星河梦瑾15 分钟前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富19 分钟前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想20 分钟前
JMeter 使用详解
java·jmeter
言、雲23 分钟前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
OopspoO28 分钟前
qcow2镜像大小压缩
学习·性能优化
TT哇30 分钟前
【数据结构练习题】链表与LinkedList
java·数据结构·链表