IO 和NIO有什么区别?

news/2025/2/27 10:46:38

IO 与 NIO 的区别详解

Java 中的 IO(Input/Output) 和 NIO(New IO 或 Non-blocking IO) 是两种不同的输入输出处理机制,主要区别体现在设计模型、性能优化和应用场景上。以下是详细对比:


1. 阻塞与非阻塞模型
  • 传统 IO阻塞式。线程调用 read() 或 write() 时会被阻塞,直到数据完成读写,期间线程无法执行其他操作。

    • 示例:服务端使用 ServerSocket 的 accept() 会阻塞线程,直到客户端连接。

  • NIO非阻塞式。线程通过通道(Channel)发起读写请求后,可立即返回结果(如 SocketChannel.read() 返回读取的字节数或 0),若数据未就绪,线程可处理其他任务。

    • 适用场景:高并发服务器(如聊天室),单线程可管理多个连接。


2. 数据处理方式
  • IO:基于流(Stream),单向流动(如 InputStream 只能读,OutputStream 只能写),逐字节处理数据,灵活性较低。

  • NIO:基于通道(Channel)和缓冲区(Buffer),数据需先读入缓冲区再处理,支持双向读写(如 FileChannel 可同时读写)。

    • 缓冲区操作:通过 flip() 切换读写模式,rewind() 重读数据,clear() 清空缓冲区。

    • 示例:读取文件时,数据从 FileChannel 写入 ByteBuffer,处理后从 ByteBuffer 写回通道。


3. 多路复用机制(Selector)
  • NIO 使用 Selector(选择器) 实现单线程管理多个通道。Selector 通过轮询检测哪些通道已就绪(如可读、可写),大幅减少线程资源消耗。

    • 示例:Web 服务器通过一个线程处理数千个客户端连接。

  • IO 每个连接需独立线程处理,线程数过多时会导致上下文切换开销大,甚至内存溢出。


4. 性能与适用场景
  • IO:适合低并发、数据量大的场景(如文件传输),代码简单。

  • NIO:适合高并发、小数据量的场景(如即时通讯),通过非阻塞和选择器提升吞吐量。

    • 零拷贝技术FileChannel.transferTo() 直接将数据从磁盘发送到网络,减少 CPU 拷贝次数。

    • 内存映射文件FileChannel.map() 将文件映射到内存,直接操作内存数据提升读写效率。


5. API 复杂度
  • IO:API 简单直观,如 FileInputStream/FileOutputStream

  • NIO:API 更复杂,需管理缓冲区、通道、选择器,开发难度较高。

    • 需处理边界条件(如缓冲区未读完的数据)、正确调用 flip()/clear() 等。


对比总结表

特性IONIO
阻塞模型阻塞式非阻塞式
数据结构流(单向)通道(双向) + 缓冲区
多路复用不支持支持(Selector 管理多个 Channel)
线程模型一连接一线程单线程处理多连接
适用场景低并发、大数据量(如文件传输)高并发、小数据量(如即时通讯服务器
高级特性内存映射文件、零拷贝

代码示例

传统 IO 读取文件:

try (FileInputStream fis = new FileInputStream("file.txt")) {
    int data;
    while ((data = fis.read()) != -1) {
        System.out.print((char) data);
    }
}

NIO 读取文件:

try (FileChannel channel = FileChannel.open(Paths.get("file.txt"))) {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    while (channel.read(buffer) > 0) {
        buffer.flip();  // 切换为读模式
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear(); // 清空缓冲区,准备下一次写入
    }
}

总结

  • IO 适合简单的阻塞式任务,开发简单但资源消耗高。

  • NIO 在需要高并发和非阻塞处理时优势明显,但需处理更复杂的 API 和边界条件。选择时需根据具体场景权衡。


http://www.niftyadmin.cn/n/5869973.html

相关文章

【C++笔记】C++11智能指针的使用及其原理

【C笔记】C11智能指针的使用及其原理 🔥个人主页:大白的编程日记 🔥专栏:C笔记 文章目录 【C笔记】C11智能指针的使用及其原理前言1.智能指针的使用场景分析2. RAII和智能指针的设计思路3. C标准库智能指针的使用4. 智能指针的原…

CentOS 7 日志切割实战:Logrotate 详解与配置指南

文章目录 CentOS 7 日志切割实战:Logrotate 详解与配置指南Logrotate 简介安装与配置文件确认安装配置文件结构 核心配置参数详解实战配置案例案例1:Nginx 日志切割案例2:按大小切割应用日志案例3:Java 程序日志 test.log 切割配置…

Nginx安装并配置https

一、安装nginx 1、nginx压缩包上传到 /usr/local目录下 2、解压Nginx 压缩包 cd /usr/local tar -zxvf nginx-1.19.2.tar.gz 3、配置 Nginx 编译选项 cd nginx-1.19.2 ./configure 4、编译和安装 Nginx make make install 5、启动 Nginx cd /usr/local/nginx/sbin…

Feign 类型转换问题解析:如何正确处理 `ResponseEntity<byte[]>` 返回值

在微服务架构中,Feign 是一种常见的用于服务间调用的客户端,它允许我们通过声明式接口来调用远程服务。使用 Feign 时,我们通常通过接口方法的返回类型来接收服务的响应体。然而,某些情况下,我们会遇到 Feign 无法正确解析响应体类型的问题,尤其是当服务返回一个如 Respo…

局部适应的分子标记筛选

各种方法被用来揭示与适应性进化一致的分子印记。FST离群值分析(fst)扫描基因组以寻找基因座特异性效应,假设其反映了多样化或平衡选择,如较高的(阳性离群值)或更低(负离群值)遗传分化(FST)与中性背景水平相比,分别(Beaumont & Balding, 2004; Beaumont & N…

计算机毕业设计SpringBoot+Vue.js中小型医院网站(源码+文档+PPT+讲解)

温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…

smolagents学习笔记系列(七)Examples-Self-correcting Text-to-SQL

这篇文章锁定官网教程中 Examples 章节中的 Self-correcting Text-to-SQL 文章,主要介绍了如何使用 Agent 对数据库进行查找。 官网链接:https://huggingface.co/docs/smolagents/v1.9.2/en/examples/text_to_sql; 【注意事项】&#xff1a…

页面中指定元素进入全屏退出全屏

可运行demo <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Fullscreen Div Example</title>…