某个SelectionKey处理完之后,怎么避免下次循环重复处理

来源:7-10 NIO服务器Thread优化-4

向松__

2018-11-14

我看老师的逻辑是每处理一个SelectionKey,都要取消一次,然后下次读取的时候都重新调用key.interestOps继续监听。这样是可避免重复处理,但是这样的同步操作,重复的多了也不太好吧。
以下是老师的取消注册代码:

private static void handleSelection(SelectionKey key, int keyOps,
                                        HashMap<SelectionKey, Runnable> map,
                                        ExecutorService pool) {
        // 重点
        // 取消继续对keyOps的监听
        key.interestOps(key.readyOps() & ~keyOps);

        Runnable runnable = null;
        try {
            runnable = map.get(key);
        } catch (Exception ignored) {

        }

        if (runnable != null && !pool.isShutdown()) {
            // 异步调度
            pool.execute(runnable);
        }
    }

但是我查了一些资料,大部分是通过以下方式避免重复处理的:

Set selectedKeys = selector.selectedKeys();
Iterator it = selectedKeys.iterator();
 
while (it.hasNext()) {
     SelectionKey key = (SelectionKey)it.next();
     // ... deal with I/O event ...
	 
	 it.remove();  //调用迭代器的 remove() 方法来删除处理过的 SelectionKey
}
写回答

1回答

Qiujuer

2018-11-14

我可以100%的明确的告诉你 你百度到的代码有问题,不信你可以试试运行一下。
用一个客户端给他发送消息,持续发送,同时在处理io的位置使用多线程异步处理。
100%会出现多线程任务队列加入一大堆的任务进去。

而且都是一个客户端的读取,到时候多线程并发也会导致读取数据错乱。

你百度的版本不适合多线程使用,说白了,处理部分逻辑如果是同步处理,也就是同时有3个客户端来消息了,他需要一个个读取,然后再读取下一个的,而且他没有移除监听,只是移除了本次的状态而已。

他这个对于客户端量少来说没啥问题,多了,并且同时来消息时只能一个读取了再读取下一个,会消耗很多时间,不能发挥多线程的优势。

而我那边那个自然也有性能问题,但是两者对比起来更优,我的方案也是mina的早期做法。

后面12章节会讲解这个部分优化。

2
4
慕桂英85875
回答的非常棒
2019-07-16
共4条回复

Socket网络编程进阶与实战 系统掌握Socket核心技术

理论+实践,系统且深入掌握Socket核心技术,从容应对各种Socket应用场景的不二之选

2316 学习 · 476 问题

查看课程