Nio和Io的区别

本文通过类比餐厅服务模式,生动地解释了NIO(非阻塞I/O)的工作原理,以及Selector如何帮助少量线程高效处理大量连接请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文原文来之http://blog.youkuaiyun.com/zhouhl_cn/article/details/6568119

 

传统的socket IO中,需要为每个连接创建一个线程,当并发的连接数量非常巨大时,线程所占用的栈内存和CPU线程切换的开销将非常巨大。使用NIO,不再需要为每个线 程创建单独的线程,可以用一个含有限数量线程的线程池,甚至一个线程来为任意数量的连接服务。由于线程数量小于连接数量,所以每个线程进行IO操作时就不 能阻塞,如果阻塞的话,有些连接就得不到处理,NIO提供了这种非阻塞的能力。

 

小量的线程如何同时为大量连接服务呢,答案就是就绪选择。这就好比到餐厅吃饭,每来一桌客人,都有一个服务员专门为你服务,从你到餐厅到结帐走人, 这样方式的好处是服务质量好,一对一的服务,VIP啊,可是缺点也很明显,成本高,如果餐厅生意好,同时来100桌客人,就需要100个服务员,那老板发 工资的时候得心痛死了,这就是传统的一个连接一个线程的方式。

 

老板是什么人啊,精着呢。这老板就得捉摸怎么能用10个服务员同时为100桌客人服务呢,老板就发现,服务员在为客人服务的过程中并不是一直都忙 着,客人点完菜,上完菜,吃着的这段时间,服务员就闲下来了,可是这个服务员还是被这桌客人占用着,不能为别的客人服务,用华为领导的话说,就是工作不饱 满。那怎么把这段闲着的时间利用起来呢。这餐厅老板就想了一个办法,让一个服务员(前台)专门负责收集客人的需求,登记下来,比如有客人进来了、客人点菜 了,客人要结帐了,都先记录下来按顺序排好。每个服务员到这里领一个需求,比如点菜,就拿着菜单帮客人点菜去了。点好菜以后,服务员马上回来,领取下一个 需求,继续为别人客人服务去了。这种方式服务质量就不如一对一的服务了,当客人数据很多的时候可能需要等待。但好处也很明显,由于在客人正吃饭着的时候服 务员不用闲着了,服务员这个时间内可以为其他客人服务了,原来10个服务员最多同时为10桌客人服务,现在可能为50桌,60客人服务了。

 

这种服务方式跟传统的区别有两个:

1、增加了一个角色,要有一个专门负责收集客人需求的人。NIO里对应的就是Selector。

2、由阻塞服务方式改为非阻塞服务了,客人吃着的时候服务员不用一直侯在客人旁边了。传统的IO操作,比如read(),当没有数据可读的时候,线程一直阻塞被占用,直到数据到来。NIO中没有数据可读时,read()会立即返回0,线程不会阻塞。

 

NIO中,客户端创建一个连接后,先要将连接注册到Selector,相当于客人进入餐厅后,告诉前台你要用餐,前台会告诉你你的桌号是几号,然后 你就可能到那张桌子坐下了,SelectionKey就是桌号。当某一桌需要服务时,前台就记录哪一桌需要什么服务,比如1号桌要点菜,2号桌要结帐,服 务员从前台取一条记录,根据记录提供服务,完了再来取下一条。这样服务的时间就被最有效的利用起来了。

<think>嗯,用户问的是NIOIO区别,这得从Java的输入输出机制说起。首先,IO指的是传统的Java I/O,也就是阻塞式I/O,而NIO是New I/O,在Java 1.4引入的非阻塞式I/O。我需要先回忆这两个的基本概念,然后对比它们的不同点。 首先,IO是阻塞的,这意味着当一个线程执行读或写操作时,线程会被阻塞,直到数据准备好或者数据传输完成。这在处理多个连接时,可能需要为每个连接创建一个线程,导致资源消耗大。比如,用ServerSocketSocket的时候,每个客户端连接都会占用一个线程,如果连接数很高,线程数量会爆炸,影响性能。 而NIO是非阻塞的,它使用通道(Channel)缓冲区(Buffer)来进行数据传输,还有Selector机制。线程可以注册多个通道到Selector上,然后通过轮询Selector来检查哪些通道已经准备好进行I/O操作。这样单个线程就可以处理多个连接,提高了效率,适合高并发场景。 接下来是数据流的处理方式。IO是面向流的,意味着数据按顺序处理,不能随意移动指针。而NIO的Buffer是面向块的,数据被读入缓冲区后可以在其中前后移动,增加了灵活性。 然后是API的不同。IO提供的是InputStreamOutputStream这样的类,而NIO有Channel、Buffer、Selector这些组件。Selector是关键,允许单线程管理多个通道,实现非阻塞。 应用场景方面,IO适合连接数较少且数据传输量大的情况,比如文件处理。NIO适合需要处理大量并发连接,但每个连接数据量不大的情况,比如聊天服务器或者实时通信系统。 不过可能用户对阻塞非阻塞的具体表现不太清楚,需要举例子说明。比如,当使用IO的read()方法时,线程会一直等待数据到达,期间不能做其他事情。而NIO的通道配置成非阻塞模式后,调用read()会立即返回,不管有没有数据,线程可以继续处理其他通道。 另外,NIO的零拷贝特性可能也是优势之一,比如使用FileChannel.transferTo()方法,可以减少数据在用户空间内核空间的拷贝次数,提升性能。 需要检查是否遗漏了什么关键点,比如缓冲区的使用方式,事件驱动模型,或者NIO的复杂性更高,编程难度大。可能用户在实际选择时需要权衡易用性性能。 总结起来,区别主要在阻塞与非阻塞、流与块的处理方式、API结构以及适用场景。需要把这些点分清楚,用用户容易理解的语言解释,避免太技术化的术语,同时确保准确。</think>### NIOIO区别(Java 场景) #### 1. **基本模型** - **IO(阻塞式 I/O)**: 基于**流(Stream)**的同步阻塞模型。线程在读写数据时会被阻塞,直到操作完成。 例如:调用 `InputStream.read()` 时,线程会一直等待数据就绪。 - **NIO(非阻塞式 I/O)**: 基于**通道(Channel)****缓冲区(Buffer)**的同步非阻塞模型。通过 `Selector` 机制,单线程可监听多个通道的事件(如连接、读写),避免线程阻塞。 例如:线程通过轮询 `Selector` 检查哪些通道已就绪,再处理数据。 --- #### 2. **核心组件对比** | **组件** | **IO** | **NIO** | |-------------------|-------------------------------------|--------------------------------------| | 数据载体 | 流(单向:`InputStream/OutputStream`) | 通道(双向:`Channel`) + 缓冲区(`Buffer`) | | 阻塞性 | 阻塞(线程等待数据) | 非阻塞(线程可处理其他任务) | | 多路复用 | 不支持(需多线程) | 支持(通过 `Selector` 单线程管理多通道) | | 数据操作灵活性 | 流式顺序读写 | 缓冲区支持随机读写(通过 `position` 指针) | --- #### 3. **适用场景** - **IO 适用场景**: - 简单连接、低并发(如文件传输)。 - 代码简单直观,无需复杂事件驱动。 - **NIO 适用场景**: - 高并发、短连接(如即时通讯、聊天服务器)。 - 需要减少线程资源消耗的场景(如百万级连接)。 --- #### 4. **性能差异** - **IO 瓶颈**: 每个连接需独立线程处理,线程切换内存开销大。 公式:$$ \text{线程数} \propto \text{连接数} $$ - **NIO 优化**: 单线程通过 `Selector` 管理多通道,减少线程资源占用。 公式:$$ \text{线程数} \ll \text{连接数} $$ --- #### 5. **代码示例** - **IO 读取文件**: ```java try (FileInputStream fis = new FileInputStream("file.txt")) { int data; while ((data = fis.read()) != -1) { // 阻塞直到数据就绪 System.out.print((char) data); } } ``` - **NIO 读取文件**: ```java try (FileChannel channel = FileChannel.open(Paths.get("file.txt"))) { ByteBuffer buffer = ByteBuffer.allocate(1024); while (channel.read(buffer) != -1) { // 非阻塞,立即返回 buffer.flip(); while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } buffer.clear(); } } ``` --- #### 6. **总结** | **维度** | **IO** | **NIO** | |----------------|-----------------------|---------------------------| | 模型 | 阻塞 | 非阻塞 + 多路复用 | | 数据操作 | 单向流 | 双向通道 + 缓冲区随机访问 | | 线程效率 | 低(线程数=连接数) | 高(单线程处理多连接) | | 适用场景 | 低并发、大数据量 | 高并发、小数据包 | 选择建议: - 需要简单性 → **IO** - 需要高并发 → **NIO**(或更高级框架如 Netty)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值