传统的socket IO中,须要为每一个链接建立一个线程,当并发的链接数量很是巨大时,线程所占用的栈内存和CPU线程切换的开销将很是巨大。使用NIO,再也不须要为每一个线程建立单独的线程,能够用一个含有限数量线程的线程池,甚至一个线程来为任意数量的链接服务。因为线程数量小于链接数量,因此每一个线程进行IO操做时就不能阻塞,若是阻塞的话,有些链接就得不处处理,NIO提供了这种非阻塞的能力。java
小量的线程如何同时为大量链接服务呢,答案就是就绪选择。这就比如到餐厅吃饭,每来一桌客人,都有一个服务员专门为你服务,从你到餐厅到结账走人,这样方式的好处是服务质量好,一对一的服务,VIP啊,但是缺点也很明显,成本高,若是餐厅生意好,同时来100桌客人,就须要100个服务员,那老板发工资的时候得心痛死了,这就是传统的一个链接一个线程的方式。git
老板是什么人啊,精着呢。这老板就得捉摸怎么能用10个服务员同时为100桌客人服务呢,老板就发现,服务员在为客人服务的过程当中并非一直都忙着,客人点完菜,上完菜,吃着的这段时间,服务员就闲下来了,但是这个服务员仍是被这桌客人占用着,不能为别的客人服务,用华为领导的话说,就是工做不饱满。那怎么把这段闲着的时间利用起来呢。这餐厅老板就想了一个办法,让一个服务员(前台)专门负责收集客人的需求,登记下来,好比有客人进来了、客人点菜了,客人要结账了,都先记录下来按顺序排好。每一个服务员到这里领一个需求,好比点菜,就拿着菜单帮客人点菜去了。点好菜之后,服务员立刻回来,领取下一个需求,继续为别人客人服务去了。这种方式服务质量就不如一对一的服务了,当客人数据不少的时候可能须要等待。但好处也很明显,因为在客人正吃饭着的时候服务员不用闲着了,服务员这个时间内能够为其余客人服务了,原来10个服务员最多同时为10桌客人服务,如今可能为50桌,60客人服务了。github
这种服务方式跟传统的区别有两个: 一、增长了一个角色,要有一个专门负责收集客人需求的人。NIO里对应的就是Selector。 二、由阻塞服务方式改成非阻塞服务了,客人吃着的时候服务员不用一直侯在客人旁边了。传统的IO操做,好比read(),当没有数据可读的时候,线程一直阻塞被占用,直到数据到来。NIO中没有数据可读时,read()会当即返回0,线程不会阻塞。数据库
NIO中,客户端建立一个链接后,先要将链接注册到Selector,至关于客人进入餐厅后,告诉前台你要用餐,前台会告诉你你的桌号是几号,而后你就可能到那张桌子坐下了,SelectionKey就是桌号。当某一桌须要服务时,前台就记录哪一桌须要什么服务,好比1号桌要点菜,2号桌要结账,服务员从前台取一条记录,根据记录提供服务,完了再来取下一条。这样服务的时间就被最有效的利用起来了。 --------上面描述引用自http://blog.csdn.net/zhouhl_cn/article/details/6568119 在实际的应用中,NIO的使用也是遍及java的框架中,我这边主要对Netty的NIO的应用进行简要的介绍:源码地址https://github.com/netty/netty, 网络
在上图的网络模型中,去掉线程池的形式,就是 是Netty NIO的默认模式。在实现上,Netty中的Boss类充当mainReactor,NioWorker类充当subReactor(默认 NioWorker的个数是Runtime.getRuntime().availableProcessors())。在处理新来的请求 时,NioWorker读完已收到的数据到ChannelBuffer中,以后触发ChannelPipeline中的ChannelHandler流。并发
Netty是事件驱动的,能够经过ChannelHandler链来控制执行流向。由于ChannelHandler链的执行过程是在 subReactor中同步的,因此若是业务处理handler耗时长,将严重影响可支持的并发数。这种模型适合于像Memcache这样的应用场景,但 对须要操做数据库或者和其余模块阻塞交互的系统就不是很合适。Netty的可扩展性很是好,而像ChannelHandler线程池化的须要,能够经过在 ChannelPipeline中添加Netty内置的ChannelHandler实现类–ExecutionHandler实现,对使用者来讲只是 添加一行代码而已。对于ExecutionHandler须要的线程池模型,Netty提供了两种可 选:1) MemoryAwareThreadPoolExecutor 可控制Executor中待处理任务的上限(超过上限时,后续进来的任务将被阻 塞),并可控制单个Channel待处理任务的上限;2) OrderedMemoryAwareThreadPoolExecutor 是 MemoryAwareThreadPoolExecutor 的子类,它还能够保证同一Channel中处理的事件流的顺序性,这主要是控制事件在异步处 理模式下可能出现的错误的事件顺序,但它并不保证同一Channel中的事件都在一个线程中执行(一般也不必)。通常来 说,OrderedMemoryAwareThreadPoolExecutor 是个很不错的选择,固然,若是有须要,也能够DIY一个。框架