NIO真空下的技术

NIO在使用过程中,有很多很多问题需要注意,甚至BUG需要规避。不是经验丰富的工程师团队,不建议从头构建NIO程序,最好采用Grizzly,Netty等开源框架。本文记录了经常遇到的几个小细节,一作备忘,二为增强理解。

1. channel.close将cancel掉channel的所有SelectionKey

AbstractSelectableChannel维护一个SelectionKey数组,存储注册所得的所有SelectionKey,一旦channel.close,这里所有的SelectionKey将被cancel掉。

2. 只有非阻塞Channel才能注册,否则会报IllegalBlockingModeException

比如FileChannel不可以改为非阻塞,所以也无法注册。

3. 一个Channel在同一个Selector上注册两次,返回同一个SelectionKey

Channel注册时,会被检查是否已在当前Selector上注册过,若是,则返回注册的SelectionKey。

4. sk.interestOps操作与register操作在同一个线程

其实这不是必须的,Grizzly,Netty,和Tomcat都是这么写的,原先本人也误以为不在同一个线程会有问题,后来证明不是这样的。之所以这么写,是规避并发性能问题。AbstractSelectableChannel中有两把锁keyLock和regLock,interestOps与register操作会导致这两把锁的激烈竞争,所以都把这些操作交给注册该Channel的Reactor线程来完成。

5. selector.selectedKeys中的SelectionKey要及早清除

selectedKeys需要及时remove,否则后面select()将不阻塞,从而导致CPU 100%。

6. 不轻易注册WRITE事件

因为可写事件来得太容易,select()将很难不阻塞,从而导致CPU 100%。

7. selectionKey.cancel的延后性

取消Key只有在下一次select操作之后才会从key set中清除。

8. select()操作之前的wakeup将导致下一次的select()不阻塞。