首页  

Java NIO 注意点     所属分类 nio 浏览量 812
事件处理一定要移除key

Iterator< SelectionKey> it = selector.selectedKeys().iterator();
While(it.hasNext()){
    SelectionKey key = it.next();
    // remove key !!!
    it.remove();  
    // handle
}


Selector返回的key集合非线程安全
正确注册Channel和更新interest channel.register(selector, ops, attachment); SelectionKey.interest(ops) linux上会阻塞,需要获取selector内部锁做同步 加入缓冲队列,等待注册,reactor单线程处理 if (isReactorThread()) { channel.register(selector, ops, attachment); } else{ register.offer(new Event(channel, ops, attachment)); selector.wakeup(); } if (this.isReactorThread()) { key.interestOps(key.interestOps() | SelectionKey.OP_READ); } else { this.register.offer(new Event(key, SelectionKey.OP_READ)); selector.wakeup(); }
正确处理OP_WRITE OP_WRITE处理不当很容易导致CPU 100% OP_WRITE触发条件 socket发送缓冲区可写 远端关闭 有错误发生 正确的处理方式 仅在已经连接的channel上注册 仅在有数据可写的时候才注册 触发之后立即取消注册,否则会继续触发导致循环 处理完成后视情况决定是否继续注册 没有完全写入,继续注册 全部写入,无需注册 要写数据时才注册OP_WRITE操作 key.isWritable()是表示可写,网络不出现阻塞情况下,一直是可以写的,所认一直为true. 可以不注册OP_WRITE事件,直接写 ,注意判断返回值
正确取消注册channel channel.close(),内部会调用key.cancel() key.cancel()仅仅是将key加入cancelledKeys 直到下一次select才真正处理 并且channel的socketfd只有在真正取消注册后才会close(fd) 服务端,问题不大,select调用频繁 客户端,通常只有一个连接,关闭channel之后,没有调用select就关闭selector sockfd没有关闭,停留在CLOSE_WAIT状态 正确的处理方式,取消注册也应当作为事件交给reactor处理,及时wakeup做select 适当的时候调用selector.selectNow() Netty在超过256连接关闭的时候主动调用一次selectNow
避免同时注册OP_ACCPET和OP_READ , OP_CONNECT和OP_WRITE 不要在同一个socket同时注册多个操作
小心处理connect SocketChannel.connect 在非阻塞模式下可能返回false,一定要判断返回值 返回false,后续处理 注册channel到selector,监听OP_CONNECT事件 在OP_CONNECT触发后,调用SocketChannel.finishConnect成功后,连接才真正建立
NIO bug 已经关闭的连接一直处于就绪状态,select(timeout)不阻塞,CPU消耗100% 升级jdk 或 代码规避 channel.close()之后马上调用select Netty3,定期调用selectNow
一些建议 尽量不要尝试实现自己的nio框架 使用经过广泛实践的开源NIO框架Mina Netty xsocket 等 使用最新稳定版JDK

上一篇     下一篇
检查硬盘是否为SSD

NIO概述

第一个 NIO server 例子

Java NIO写事件处理技巧

java NIO buffer

Java NIO pipe