java NIO的讨论
1.优点:NIO框架性能表现得好与坏,更多的是作者在一些细节方面的处理。
NIO框架其实内部的核心实现都差不多, 比如在Server端通常开有Acceptor和Poller线程,
Acceptor负责接收请求,得到一个Socket后把它包装一下,比如放到一个Task中,然后再把Task加到一个Queue,
Poller说白了就是在不停的执行一个循环,在这个循环中处理各种Task,Task除了Acceptor新注册的任务外,当然还有读和写。
比如在读写字节时尽量减少来回copy,这方面一些成熟的框架都做得很好了,
比如Tomcat、Jetty、Netty在从Socket中读取字节时一般都自已实现了一套Buffer类来对字节数组进行操作,
而不是直接使用java.nio中的Buffer类,
如果想从Buffer中抽取一个片段(比如在http协议解析中,一个请求行有method,uri,http-version),
只要把offset和片段length记下来就行了。
另一个就是并发问题了,尽量减少不必要的同步,
比如像上面的Queue就是一个很关键的地方,这个地方一般会有三种线程在对它操作,
1. Acceptor把接收到的Socket包装成Task加到Queue(执行Queue.offer)
2. 应用线程要写数据,所以WriteTask也会加到Queue(执行Queue.offer)
3. Poller从Queue中取出Task来执行(执行Queue.poll)
所以这个Queue的实现就很重要了,
Netty的聪明之处在于,它没有使用java.util.concurrent中的Queue实现(比如ArrayBlockingQueue或ConcurrentLinkedQueue),
而是使用Doug Lea大神在jdk1.7中才加入的jsr166y.LinkedTransferQueue,
在Netty中变成了org.jboss.netty.util.internal.LinkedTransferQueue,这两个类有一点点差异,
我无法确认是Trustin Lee自己修改的,还是用了不同版本。
jsr166y.LinkedTransferQueue威力不容忽视,Tomcat、Jetty、Mina都没使用,
如果你刚好又用过BoneCP(一个JDBC数据库链接池框架),它也用了jsr166y.LinkedTransferQueue来对链接进行offer和poll操作,
BoneCP的测试报告出来了(http://jolbox.com/),比DBCP、C3P0快20多倍。
2.缺点:
Netty的一个缺点,
大家看到这,发现我都没有提到读数据的情况,Netty读数据也是用Poller线程在读,
不管Acceptor放入多少个Socket,全是Poller线程在一个个地读,
把读到的数据放到Buffer后会触发MessageEvent事件(Netty是一个纯正的事件驱动框架,这是Tomcat、Jetty这类业余选手望尘莫及的),
此时会调用ChannelUpstreamHandler这类处理器的messageReceived方法,
messageReceived方法中的代码通常是业务相关的,但是执行messageReceived方法的线程却是Poller线程,
所以只要在messageReceived这种地方出现问题,比如有个Thead.sleep调用或者出现无限循环,
那么此时Netty跟死了没分别,Poller线程无法往下走了,所有Task都没法处理了