NIO与传统IO的区别(概述)

传统的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

### ### NIO中的IO多路复用模型原理及实现 IO多路复用是一种允许单个线程管理多个I/O通道的技术,通过监听多个I/O事件(如连接建立、数据到达等),并在事件触发时进行相应的处理,从而提高系统的效率和性能。这种技术特别适用于高并发场景,例如处理大量连接请求时,能够显著减少线程切换的开销并提升系统吞吐量[^3]。 在Java NIO中,IO多路复用主要通过`Selector`类实现。`Selector`可以监听多个`Channel`的状态变化,当某个`Channel`准备好进行I/O操作时,`Selector`会通知相应的线程进行处理。这种方式使得一个线程可以管理多个网络连接,避免了为每个连接分配单独线程所带来的资源消耗问题[^4]。 #### 原理概述 IO多路复用的核心在于事件驱动机制。它通过注册感兴趣的I/O事件(如读就绪、写就绪、连接完成等)到`Selector`上,然后调用`select()`方法阻塞等待这些事件的发生。一旦有事件触发,`select()`方法会返回所有已经就绪的`Channel`,应用程序可以对这些`Channel`进行处理。这种方式实现了非阻塞式的I/O操作,提高了资源利用率[^2]。 #### 实现细节 Java NIO的`Selector`和`Channel`配合使用,具体步骤如下: 1. **创建Selector**:首先需要创建一个`Selector`实例,它是多路复用的核心组件。 2. **打开Channel**:每个网络连接都对应一个`SocketChannel`或`ServerSocketChannel`,它们需要设置为非阻塞模式。 3. **注册Channel到Selector**:将`Channel`注册到`Selector`上,并指定监听的事件类型。 4. **轮询事件**:调用`Selector.select()`方法进入阻塞状态,直到有事件发生。 5. **处理事件**:当`select()`返回时,遍历所有已就绪的`Channel`,并对相应的事件进行处理。 以下是一个简单的Java NIO多路复用实现示例: ```java import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; public class NIOServer { public static void main(String[] args) throws IOException { // 创建Selector Selector selector = Selector.open(); // 打开ServerSocketChannel ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(8080)); serverSocketChannel.configureBlocking(false); // 设置为非阻塞 // 注册到Selector serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { // 阻塞等待事件 int readyChannels = selector.select(); if (readyChannels == 0) continue; // 获取所有就绪的SelectionKey Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { // 处理新连接 ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel(); SocketChannel clientChannel = serverChannel.accept(); clientChannel.configureBlocking(false); clientChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 处理读事件 SocketChannel clientChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(256); int bytesRead = clientChannel.read(buffer); if (bytesRead == -1) { clientChannel.close(); // 连接关闭 } else { buffer.flip(); System.out.println("Received: " + new String(buffer.array()).trim()); } } keyIterator.remove(); // 移除处理过的key } } } } ``` #### 优势应用场景 IO多路复用模型的优势在于其高效的并发处理能力。通过单个线程管理多个I/O通道,减少了线程创建和切换的成本,使得系统能够更好地应对高并发请求。尤其在处理成千上万的连接时,这种模型可以显著提升性能。然而,它并不适用于所有场景,例如在低并发环境下,传统的阻塞I/O可能更加简单且效率足够。 此外,IO多路复用模型在实际应用中也存在一定的复杂性。开发人员需要熟悉非阻塞编程模式,并合理管理`Selector`和`Channel`的状态,以确保程序的正确性和稳定性。尽管如此,对于需要高性能网络服务的应用来说,掌握IO多路复用技术仍然是非常有价值的。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值