zoukankan      html  css  js  c++  java
  • Java NIO问题记录:当channel就绪,select()依然返回0?

    问题

    今天调试NIO后台发现一个蛋疼的问题。经过调试之后,出现问题的流程描述如下:

    客户端向服务端发送消息,服务端使用IO多路复用处理输入,即一个selector监听多个channel。第一条消息正常接收,发送第二条消息时,select()立即返回0,然后开始continue无限循环,导致第二条消息无法正常处理。

    下方是服务端处理select()的代码(由一个异步线程处理)即read监听线程

    while (!isClosed.get()) {
        if (readSelector.select() == 0) {
            //这里有一个等待操作,等待注册结束
            waitSelection(inRegInput);
            continue;
        }
        Iterator<SelectionKey> iterator = readSelector.selectedKeys().iterator();
        while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            if (key.isValid()) {
                // 取消继续对keyOps的监听
                key.interestOps(key.readyOps() & ~SelectionKey.OP_READ);
                //线程池执行read操作
                inputHandlePool.execute(new InputHandlerImpl(key));
            }
        }
    }
    

    按理说,有新的channel就绪时,select()会返回大于0的数,或者没有channel就绪,select()也是保持阻塞状态,不会有返回。可现在问题是,为什么它立即返回0了?

    原因

    在Stack Overflow上找到了答案:

    Java NIO Selector select() returns 0 although channels are ready

    其实select()是否返回与selectedKeys集合有关。当selectedKeys集合不为空时,select()会立即返回,但是其返回值是发生改变的keys数量,即新的就绪通道数量,这里不可能是1。因此我的这个场景下,第一条消息会产生一个新的key,我处理完没有将其删除,所以收第二条消息时,认定这个key没有发生改变,就会导致select()返回0,从而导致无限循环。所以,一定要把key从selectedKeys集合中移除。

    解决方法:很简单,遍历迭代器的循环中加一句iterator.remove()移除已处理的key。代码如下:

    while (iterator.hasNext()) {
        SelectionKey key = iterator.next();
        iterator.remove();
        ......
    }
    
  • 相关阅读:
    python3 字典的常用方法
    python3 列表的常用方法
    【自动化测试之路】目录
    《Python编程从入门到实践》练习题
    【python3】第20章设置项目“学习笔记”的样式
    【python3】第19章用户账户
    【python3】第18章Django入门
    【python3】第15章生成数据
    【python3】第12~14章外星人入侵
    【python3】第10章文件
  • 原文地址:https://www.cnblogs.com/buptleida/p/12713514.html
Copyright © 2011-2022 走看看