NIO与传统IO的区别--通熟易懂,很经典

本文通过类比餐厅服务方式,生动地解释了NIO(非阻塞IO)与传统IO的区别。NIO通过就绪选择机制和服务线程池,实现了少量线程高效处理大量连接的目的。

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

传统的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号桌要结帐,服务员从前台取一条记录,根据记录提供服务,完了再来取下一条。这样服务的时间就被最有效的利用起来了。


本文转自:http://blog.youkuaiyun.com/zhouhl_cn/article/details/6568119

还有一篇文章讲的比较清楚:http://ifeve.com/java-nio-vs-io/

### Java NIO传统IO区别 #### 数据处理方式 传统IO是基于流(Stream)的,数据被逐字节或逐组字节地读取或写入。相比之下,NIO是基于缓冲区(Buffer)的,所有的数据都必须先放到缓冲区中再进行读写操作[^5]。 #### 阻塞特性 传统IO的操作常是阻塞式的,在调用`read()`或其他方法时,线程会被挂起直到完成相应的I/O操作。而NIO支持非阻塞模式,即使没有数据可读也不会阻塞程序运行,而是立即返回。 #### 底层实现机制 在传统IO中,每个客户端连接都需要创建一个新的线程来处理该连接的读写请求;而在NIO中,过引入选择器(Selector),单个线程可以管理多个道(Channel)。这种多路复用技术极大地提升了系统的并发能力资源利用率[^2]。 #### 文件操作 对于文件读写而言,虽然两者都可以胜任基本的任务需求,但在某些特定情况下各有千秋。例如,NIO提供了内存映射功能,可以让部分甚至整个文件直接映射至内存地址空间内快速访问,这对于大规模随机存取非常有利。 #### 网络信 在网络编程领域,由于传统IO采用了一种简单的一对一线程模型,因此当面对海量短时间内的瞬态链接时表现不佳——过多的上下文切换开销会让CPU负载过高并最终拖垮服务性能。相反地,借助于非阻塞API以及事件驱动架构设计思路下的NIO,则能够在相同硬件条件下支撑更多活跃用户同时在线交互活动[^4]。 --- ### 使用场景分析 - **低并发环境** 如果应用程序只需要应对少量长期存在的稳定连接,则可以选择较为简单的传统IO方案,因为它具有更清晰易懂的设计逻辑结构,并且维护成本较低[^5]。 - **高并发环境** 当涉及到大量短暂生命周期类型的网络请求处理任务时,应该优先考虑运用具备更高扩展性的NIO框架解决方案,以便充分利用有限计算资源达到最佳吞吐量效果[^4]。 - **大数据传输** 在涉及频繁的大批量数据交换过程中,比如视频直播平台推送实时画面帧序列给观众终端设备显示出来等情况之下,利用NIO所提供的高效缓冲机制配合恰当算法优化策略往往可以获得优于常规做法的表现水平[^3]。 --- ```java // Traditional IO Example import java.io.*; public class TraditionalIoExample { public static void main(String[] args) throws IOException { try (FileInputStream fis = new FileInputStream("file.txt"); BufferedInputStream bis = new BufferedInputStream(fis)) { int data; while ((data = bis.read()) != -1) { System.out.print((char)data); } } } } // NIO Example import java.nio.file.*; import java.nio.channels.*; import java.nio.ByteBuffer; public class NioExample { public static void main(String[] args) throws Exception{ FileChannel fc = FileChannel.open(Paths.get("file.txt"), StandardOpenOption.READ); ByteBuffer buffer = ByteBuffer.allocate(1024); while(fc.read(buffer) > 0){ buffer.flip(); while(buffer.hasRemaining()){ System.out.print((char)buffer.get()); } buffer.clear(); } fc.close(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值