Java IO编程全解(六)——4种I/O的对比与选型
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7804185.html
为了防止由于对一些技术概念和术语的理解或者叫法不一致而引起歧义,这里对涉及到的专业术语或者技术用语做下声明:如果它们与其他一些地方的称呼不一致,请以本解释为准。
异步非阻塞I/O
很多人喜欢将JDK1.4提供的NIO框架成为异步非阻塞I/O,但是,如果严格按照UNIX网络编程模型和JDK的实现进行区分,实际上它只能被称为非阻塞I/O,不能叫异步非阻塞I/O。在早期的JDK1.4和1.5 update10版本之前,JDK的Selector基于select/poll模型实现,它是基于I/O复用技术的非阻塞I/O,不是异步I/O。在JDK1.5 update10和Linux core2.6以上版本,Sun优化了Selector实现,它在底层使用epoll替换了select/poll,上层的API并没有变化,可以认为是JDK NIO的一次性能优化,但是它仍旧没有改变I/O的模型。
由JDK1.7提供的NIO 2.0,新增了异步的套接字通道,它是真正的异步I/O,在异步I/O操作的时候可以传递信号变量,当操作完成之后会回调相关的方法,异步I/O也被称为AIO。
NIO类库支持非阻塞读和写操作,相比于之前的同步阻塞读和写,它是异步的,NIO类库支持非阻塞读和写操作,相比于之前的同步阻塞读和写,它是一部的,因此很多人习惯称NIO为异步非阻塞I/O,包括很多介绍NIO编程的书籍也沿用了这个说法。为了符合大家的习惯,这里也会将NIO称为异步非阻塞I/O或者非阻塞I/O。请大家理解,不要过分纠结在一些技术术语的咬文嚼字上。
多路复用器Selector
几乎所有的中文技术书籍都将Selector翻译为选择器,但是实际上我认为这样的翻译并不恰当,选择器仅仅是字面上的意思,体现不出Selector的功能和特点。
前面介绍过Java NIO的实现关键是多路复用I/O技术,多路复用的核心就是通过Selector来轮询注册在其上的Channel,当发现某个或者多个Channel处于就绪状态后,从阻塞状态返回就绪的Channel的选择键集合,进行I/O操作。由于多路复用器是NIO实现非阻塞I/O的关键,它又是主要通过Selector实现的,所以这里将Selector翻译为多路复用器,与其他技术书籍所说的选择器是同一个东西,请大家了解。
伪异步I/O
伪异步的概念完全来源于实现。在JDK NIO编程没有流行之前,为了解决Tomcat通信线程同步I/O导致业务线程被挂住的问题,大家想到了一个办法:在通信线程和业务线程之前做个缓冲区,这个缓冲区用于隔离I/O线程和业务线程间的直接访问,这样业务线程就不会被I/O线程阻塞。而对于后端的业务侧来说,将消息或者Task放到线程池后就返回了,它不再直接访问I/O线程或者进行I/O读写,这样就不会被同步阻塞。类似的设计还包括前端启动一组线程,将接收到的客户端封装成Task,放到后端的线程池执行,用于解决一连接一线程问题。像这样通过线程池做缓冲区的做法,这里习惯于称它为伪异步I/O,而官方并没有伪异步I/O这种说法,请大家注意。
1. 不同I/O模型对比
不同的I/O模型由于线程模型、API等差别很大,所以用法的差异也非常大。

实际开发中,具体选择什么样的I/O模型或者NIO框架,完全基于业务的实际应用场景和性能诉求,如果客户端并发连接数不多,周边对接的网元不多,服务器的负载也不重,那就完全没必要选择NIO做服务器;如果是相反情况,那就要考虑选择合适的NIO框架进行开发。
2.选择Netty的理由
开发出高质量的NIO程序并不是一件简单的事情,除去NIO固有的复杂性和BUG不谈,作为一个NIO服务器,需要能够处理网络的闪断、客户端的重复接入、客户端的安全认证、消息的编解码、半包读写等情况,如果你没有足够的NIO编程经验积累,一个NIO框架的稳定往往需要半年甚至更长的时间。更为糟糕的是,一旦在生产环境中发生问题,往往会导致跨节点的服务调用中断,严重的可能会导致整个集群环境都不可用,需要重启服务器,这种非正常停机会带来巨大的损失。
从可维护性角度看,由于NIO采用了异步非阻塞编程模型,而且是一个I/O线程处理多条链路,它的调试和跟踪非常麻烦,特别是生产环境中的问题,我们无法进行有效的调试和跟踪,往往只能靠一些日志来辅助分析,定位难度很大。
2.1不选择Java原生NIO编程的原因
现在我们总结一下我们不建议开发者直接使用JDK的NIO类库进行开发,具体原因如下。
- NIO的类库和API繁杂,使用麻烦,你需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等。
 - 需要具备其他的额外技能做铺垫,例如熟悉Java多线程编程。这是因为NIO编程设计到Reactor模式,你必须对多线程和网络编程非常熟悉,才能编写出高质量的NIO程序。
 - 可靠性能力补齐,工作量和难度都非常大。例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理等问题,NIO编程的特点是功能开发相对容易,但是可靠性能力补齐的工作量和难度都非常大。
 - JDK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector空轮询,最终导致CPU100%,官方声称在JDK1.6版本的update18修复了该问题,但是直到JDK1.7版本该问题仍旧存在,只不过该BUG发生频率降低了一些而已,它并没有被根本解决。
 
由于上述原因,在大多数场景下,不建议大家直接使用JDK的NIO类库,除非你精通NIO编程或者有特殊的需求。在绝大多数的业务场景中,我们可以使用NIO框架Netty来进行NIO编程,它既可以作为客户端也可以作为服务端,同时支持UDP和异步文件传输,功能非常强大。
2.2为什么选择Netty
Netty是业界最流行的NIO框架之一,它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指的,它已经得到成百上千的商业项目验证,例如Hadoop的RPC框架avro使用Netty作为底层通信框架;很多其他业界主流的RPC框架,也使用Netty来构建高性能的异步通信能力。
Netty的优点总结如下:
- API使用简单,开发门槛低;
 - 功能强大,预置了多种编解码功能,支持多种主流协议;
 - 定制能力强,可以通过ChannelHandler对通信框架进行灵活地扩展;
 - 性能高,通过与其他业界主流的NIO框架对比,Netty的综合性能最优;
 - 成熟、稳定,Netty修复了已经发现的所有JDK NIO BUG,业务开发人员不需要再为NIO的BUG而烦恼;
 - 社区活跃,版本迭代周期短,发现的BUG可以被及时修复,同时,更多的新功能会加入;
 - 经历了大规模的商业应用考验,质量得到验证。在互联网、大数据、网络游戏、企业应用、电信软件等众多行业得到成功商用,证明了它已经完全能够满足不同行业的商业应用了。
 
正是因为这些优点,Netty逐渐成为Java NIO编程的首选框架。
如果此文对您有帮助,微信打赏我一下吧~

Java IO编程全解(六)——4种I/O的对比与选型的更多相关文章
- Java IO编程全解(五)——AIO编程
		
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7794151.html 前面讲到:Java IO编程全解(四)--NIO编程 NIO2.0引入了新的异步通道的 ...
 - Java IO编程全解(四)——NIO编程
		
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7793964.html 前面讲到:Java IO编程全解(三)——伪异步IO编程 NIO,即New I/O,这 ...
 - Java IO编程全解(三)——伪异步IO编程
		
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7723174.html 前面讲到:Java IO编程全解(二)--传统的BIO编程 为了解决同步阻塞I/O面临 ...
 - Java IO编程全解(二)——传统的BIO编程
		
前面讲到:Java IO编程全解(一)——Java的I/O演进之路 网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口 ...
 - Java IO编程全解(一)——Java的I/O演进之路
		
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7419117.html JDK1.4之前的早期版本,Java对I/O的支持并不完善,开发人员在开发高性能I/O ...
 - JAVA IO 类库详解
		
JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...
 - java并发编程笔记(六)——AQS
		
java并发编程笔记(六)--AQS 使用了Node实现FIFO(first in first out)队列,可以用于构建锁或者其他同步装置的基础框架 利用了一个int类型表示状态 使用方法是继承 子 ...
 - Java中的ReentrantLock和synchronized两种锁定机制的对比
		
问题:多个访问线程将需要写入到文件中的数据先保存到一个队列里面,然后由专门的 写出线程负责从队列中取出数据并写入到文件中. http://blog.csdn.net/top_code/article/ ...
 - Java IO流详解(六)——转换流
		
转换流也是一种处理流,它提供了字节流和字符流之间的转换.在Java IO流中提供了两个转换流:InputStreamReader 和 OutputStreamWriter,这两个类都属于字符流.其中I ...
 
随机推荐
- 如何写一个jquery插件
			
本文总结整理一下如何写一个jquery插件?虽然现今各种mvvm框架异常火爆,但是jquery这个陪伴我们成长,给我们带来很多帮助的优秀的库不应该被我们抛弃,写此文章,作为对以往欠下的笔记的补充, ...
 - The area  积分积分
			
The area Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Sta ...
 - Easy sssp
			
Easy sssp 时间限制: 1 Sec 内存限制: 128 MB提交: 103 解决: 20[提交][状态][讨论版] 题目描述 输入数据给出一个有N(2 < = N < = ...
 - js自执行函数写法
			
(1)写法1 (function(){ //函数内容 })() (2)写法2 (function(){ //函数内容 }())
 - Python中wx.FlexGridSizer
			
FlexGridSizer是GridSizer的一个更灵活的版本.它与标准的GridSizer几乎相同,除了下面3点例外: 1.每行和每列可以有各自的尺寸.2.默认情况下,当尺寸调整时,它行和列整体改 ...
 - 用html+css+js做打地鼠小游戏
			
html 代码 first.html <!DOCTYPE html> <html lang="en"> <head> <meta char ...
 - 【实验吧】Once More
			
<?php if (isset ($_GET['password'])) { if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) = ...
 - Windows系统下八大具有高逼格的DOS命令之一【ping】
			
ping命令: ping是用来检测网络是否通畅或者查询网络连接速度的一个基础命令.作为一名对计算机痴迷的爱好者来说,ping命令是需要第一个掌握的DOS命令.它所利用的原理是这样的:网络上的机器都有唯 ...
 - 【学习】ie8支持rgba()透明度颜色
			
(我的博客网站中的原文:http://www.xiaoxianworld.com/archives/285,欢迎遇到的小伙伴常来瞅瞅,给点评论和建议,有错误和不足,也请指出.) rgba()函数可以用 ...
 - 初学者易上手的SSH-hibernate02 三种查询方式
			
在上一章中已经搭建好了一个hibernate的环境,那么这一章我们就使用这个环境来进行基本CRUD.在这之前我们先了解一个东西:主键生成策略.就是当向数据库表中插入记录的时候,这个记录的主键该如何生成 ...