• 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();
        ......
    }
    
  • 相关阅读:
    将博客搬至CSDN
    U盘启动盘 安装双系统 详细教程
    vmware安装linux6.3
    hadoop学习之路
    linux重定向总结:如何将shell命令的输出信息自动输出到文件中保存
    AVRO讲解
    MapReduce 工作原理
    lucene索引存储原理
    ES数据库系统
    分流器设备与交换机设备的区别
  • 原文地址:https://www.cnblogs.com/buptleida/p/12713514.html
Copyright © 2020-2023  润新知