NIO中的多路复用

多路复用 对比 线程池 伪异步的优点:


使用线程池模型:
假设机器A可以开1000个线程,那最多就是1000个连接。
因为网络IO较慢且需要阻塞,此时可能有900个线程处于阻塞在网络IO处的状态。
也就是只有100个线程在干别的事情。
这样对整个机器A的所有资源都是浪费。


使用多路复用以后, 网络IO阻塞不在占用独有的线程。同样是机器A,
做实际事情的线程数可能可以开到1000, 实际做事的效率就<strong>可能</strong>要比之前高。


这里为啥是可能呢而非一定呢?
比如机器A装的是db, 这个db的100个线程就跑到了 磁盘IO瓶颈, 这时在接受新的任务(增加线程数)就不会增加效率,反而会降低效率。


下图是java中NIO的使用的示意:




当向Selector注册Channel时,register()方法会返回一个SelectionKey对象
这个对象很重要,它包含了
interest集合
ready集合
Channel  生成这个key 时, 注册的channel
Selector  生成这个key 时, 被注册的Selector
附加的对象(可选)


    SelectionKey key = keyIterator.next();
    if(key.isAcceptable()) {
        // a connection was accepted by a ServerSocketChannel.
    } else if (key.isConnectable()) {
        // a connection was established with a remote server.
    } else if (key.isReadable()) {
        // a channel is ready for reading
    } else if (key.isWritable()) {
        // a channel is ready for writing
    }
以下是基于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; import java.util.Set; public class NioMultiplexingServer { private Selector selector; public void init(int port) throws IOException { // 创建selector selector = Selector.open(); // 创建ServerSocketChannel ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); // 绑定端口 serverSocketChannel.socket().bind(new InetSocketAddress(port)); // 将ServerSocketChannel注册到selector上,并监听OP_ACCEPT事件 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Server started at port " + port); // 循环处理selector上的事件 while (true) { // 阻塞等待事件发生 int readyChannels = selector.select(); if (readyChannels == 0) { continue; } // 处理事件 Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { // 处理OP_ACCEPT事件 handleAccept(key); } else if (key.isReadable()) { // 处理OP_READ事件 handleRead(key); } keyIterator.remove(); } } } private void handleAccept(SelectionKey key) throws IOException { // 获取ServerSocketChannel ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); // 接受连接 SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); // 将SocketChannel注册到selector上,并监听OP_READ事件 socketChannel.register(selector, SelectionKey.OP_READ); System.out.println("Connection accepted: " + socketChannel.getRemoteAddress()); } private void handleRead(SelectionKey key) throws IOException { // 获取SocketChannel SocketChannel socketChannel = (SocketChannel) key.channel(); // 读取数据 ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead = socketChannel.read(buffer); if (bytesRead == -1) { // 连接已关闭 socketChannel.close(); System.out.println("Connection closed: " + socketChannel.getRemoteAddress()); return; } // 处理数据 buffer.flip(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); String message = new String(bytes); System.out.println("Message received from " + socketChannel.getRemoteAddress() + ": " + message); // 回复客户端 ByteBuffer responseBuffer = ByteBuffer.wrap(("Received message: " + message).getBytes()); socketChannel.write(responseBuffer); } public static void main(String[] args) throws IOException { NioMultiplexingServer server = new NioMultiplexingServer(); server.init(8080); } } ``` 上述代码实现了一个简单的nio多路复用服务器,其: 1. 初始化方法创建了一个Selector和一个ServerSocketChannel,并将ServerSocketChannel注册到selector上,监听OP_ACCEPT事件; 2. 循环处理selector上的事件,阻塞等待事件发生; 3. 对于每个事件,根据事件类型进行处理处理完毕后从selector的selectedKeys集合移除该事件。 在handleAccept和handleRead方法,分别处理了OP_ACCEPT和OP_READ事件: 1. handleAccept方法,获取ServerSocketChannel并接受连接,将SocketChannel注册到selector上,监听OP_READ事件; 2. handleRead方法,获取SocketChannel并读取数据,处理数据并回复客户端。 通过以上代码,我们实现了一个简单的nio多路复用服务器,可以同时处理多个连接请求
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值