Java NIO的出现  

  Java语言发展至今,优点大家有目共睹:面向对象的语言、简洁有效、高移植性等等。但是同样也存在很多缺点,C语言程序员口中Java太慢了,.net程序员口中Java太开放了,php程序员说Java太复杂了。

  Java为了“一次编写,到处运行”的最大优势,也付出了相应的代价:

  Java需要运行于虚拟机(即JVM)之上,为了保证Java字节码在各种JVM部署平台上运行效果一致,作些妥协是必须的。既然需要通用于不同的操作系统平台,那么,某种程度上就必须选择各种平台都接受的处理方案。这也就造成了Java不能发挥各种平台的特性和优化的地方。

  受到这种机制的影响最突出的莫属I/O领域了。虽然Java也提供了一套比较完备的I/O支持,但都是针对于各种平台的通用特性。这些I/O类都是面向流数据的操作,适用性广泛,但是当操作大量数据时,致命的效率缺陷也暴露无遗,这就是其他语言的程序员对JavaI/O的效率嗤之以鼻的原因。

  I/O的终极目标是效率,而效率离不开底层操作系统和文件系统的特性支持。这些特性包括:文件锁定、非阻塞I/O、就绪性选择、和内存映射。当今操作系统大都支持这些特性,而Java传统I/O机制并没有模拟这些通用的I/O服务。就好像一个武林高手内功很高,但是却没有招式发挥,只能憋着。

  好在Java语言开发者也意识到了这一点,在Java1.4版本的需求征集中,其中有一条:Java规范请求#51(JSR 51, http://jcp.org/jsr/detail/51.jsp),包含了对高速、可伸缩I/O特性的详尽描述,借助这一特性,底层操作系统的I/O性能可以得到更好发挥。

  JSR 51的实现也标志着Java New I/O(NIO)的诞生。其结果就是新增类组合到一起,构成了java.nio及其子包,以及java.util.regex软件包,同时现存软件包也相应作了几处修改。随着Java1.4版本的发布,操作系统强大的I/O特性终于可以借助Java提供的工具得到充分发挥。论及I/O性能,Java再也不逊于任何一款编程语言。

Java NIO带来了什么?

  传统Java IO在我前一篇博文《细说Java IO相关》已经介绍过了,它是阻塞的,低效的。那么Java NIO和传统Java IO有什么不同?带来了什么?

(1)面向块的I/O

  传统JavaIO是面向流的I/O。流I/O一次处理一个字节。NIO则是面向块的I/O,每次操作都是以数据块为单位。它们的差距就好象两个人吃饭,一个人一粒一粒的吃,另一个人狼吞虎咽,快慢显而易见。

  NIO中引入了缓冲区(Buffer)的概念,缓冲区作为传输数据的基本单位块,所有对数据的操作都是基于将数据移进/移出缓冲区而来;读数据的时候从缓冲区中取,写的时候将数据填入缓冲区。尽管传统JavaIO中也有相应的缓冲区过滤器流(BufferedInputStream等),但是移进/移出的操作是由程序员来包装的,它本质是对数据结构化和积累达到处理时的方便,并不是一种提高I/O效率的措施。NIO的缓冲区则不然,对缓冲区的移进/移出操作是由底层操作系统来实现的。

  通常一次缓冲区操作是这样的:某个进程需要进行I/O操作,它执行了一次读(read)或者写(write)的系统调用,向底层操作系统发出了请求,操作系统会按要求把数据缓冲区填满或者排干。说起来简单,其实很复杂。但至少我们知道了这事是由操作系统干的,比我们代码级的实现要高效的多。

  除了效率上的差别外,缓冲区在数据分析和处理上也带来的很大的便利和灵活性。

(2)非阻塞的I/O + 就绪性选择

  传统JavaIO是基于阻塞I/O模型的:当发起一个I/O请求时,如果数据没有准备好(read时无可读数据,write时数据不可写入),那么线程便会阻塞,直到数据准备好,导致线程大部分的时间都在阻塞。

  而非阻塞I/O则允许线程在有数据的时候处理数据,没有数据的时候干点别的,提高了资源利用率。

  就绪性选择通常是建立在非阻塞的基础上,并且更进一步,它把检查哪些I/O请求的数据准备好这个任务交给了底层操作系统,操作系统会去查看并返回结果集合,这样我们只需要关心那些准备好进行操作的IO通道。关于就绪性选择的过程会在后面详述。

  NIO提供的Socket可以用非阻塞的方式工作,并且支持就绪性选择,减少了资源消耗和CPU在线程间的切换,在管理线程效率上比传统Socket高。

(3)文件锁定和内存映射文件等操作系统特性

  NIO同时带来了很多当今操作系统大都支持的特性。

  文件锁定是多个进程协同工作的情况下,要协调进程间对共享数据的访问必不可少的工具。

  内存映射利用虚拟内存技术提供对文件的高速缓存,使读取磁盘文件就像从内存中读取一样高效,但是却不会有内存泄漏的危险,因为在内存中不会存在文件的完整拷贝。

  此外还有一些其他的特性,后面再详述。

为什么要使用NIO?

  显然,使用或者不使用NIO的理由不会是因为技术崇拜,因为这个东西才出来,看起来很酷我就去使用它。好吧,我承认我是有一点这样的原因。

  对于文件I/O, 在我看来使用IO和NIO是区别不大的,Java1.4开始原始IO也根据NIO重新实现过了,提供了对于NIO特性的支持。即使是流,也会比以前更加高效。企业级应用软件中涉及I/O的部分多半是读写文件的功能性需求,很少有在并发上的要求,那么JavaIO包已经很胜任了。

  对于网络I/O,传统的阻塞式I/O,一个线程对应一个连接,采用线程池的模式在大部分场景下简单高效。当连接数茫茫多时,并且数据的移动非常频繁,NIO无疑是更好的选择。

  NIO标榜的是高速、可伸缩的I/O,因为它更亲近操作系统。当需求很平凡,没有太高的效率要求的时候,你看不出它的好,反而觉得NIO代码实现复杂,不易理解。选择与否全看使用的场景,这点就看使用者的权衡了。

  

Java NIO(1):迟迟登场的NIO的更多相关文章

  1. 高吞吐高并发Java NIO服务的架构(NIO架构及应用之一)

    高吞吐高并发Java NIO服务的架构(NIO架构及应用之一) http://maoyidao.iteye.com/blog/1149015   Java NIO成功的应用在了各种分布式.即时通信和中 ...

  2. android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup

    android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup 复制netty包 ...

  3. 疯狂Java学习笔记(75)-----------NIO.2第一篇

    Java 7引入了NIO.2.NIO.2是继承自NIO框架,并添加了新的功能(比如:处理软链接和硬链接的功能).这篇帖子包含三个部分,我将使用NIO.2的一些演示样例.由此向大家演示NIO.2的基本用 ...

  4. Java网络通信方面,BIO、NIO、AIO、Netty

    码云项目源码地址:https://gitee.com/ZhangShunHai/echo 教学视频地址:链接: https://pan.baidu.com/s/1knVlW7O8hZc8XgXm1dC ...

  5. Java面试必问通信框架NIO,原理详解

    NIO 流与块 通道与缓冲区 缓冲区状态变量 文件 NIO 实例 选择器 套接字 NIO 实例 内存映射文件 NIO与IO对比 Path Files NIO 新的输入/输出 (NIO) 库是在 JDK ...

  6. Java高并发网络编程(三)NIO

    从Java 1.4开始,Java提供了新的非阻塞IO操作API,用意是替代Java IO和Java Networking相关的API. NIO中有三个核心组件: Buffer缓冲区 Channel通道 ...

  7. Java IO学习笔记六:NIO到多路复用

    作者:Grey 原文地址:Java IO学习笔记六:NIO到多路复用 虽然NIO性能上比BIO要好,参考:Java IO学习笔记五:BIO到NIO 但是NIO也有问题,NIO服务端的示例代码中往往会包 ...

  8. Java IO模型:BIO、NIO、AIO

    Java IO模型:BIO.NIO.AIO 本来是打算直接学习网络框架Netty的,但是先补充了一下自己对Java 几种IO模型的学习和理解.分别是 BIO.NIO.AIO三种IO模型. IO模型的基 ...

  9. NIO 源码分析(01) NIO 最简用法

    目录 一.服务端 二.客户端 NIO 源码分析(01) NIO 最简用法 Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) J ...

随机推荐

  1. mongodb_profier

    http://docs.mongodb.org/manual/reference/database-profiler/ 一.获取.设置profile(profile用collection存储数据) d ...

  2. JS组件系列——自己封装一个上传文件组件

    页面调用: $('#fileUpload').cemsUpload({ errorEmpty:'<s:text name="cupgrade.view.tip.upload.file. ...

  3. ExtJs 4中 Ext.Ajax.request提交实现waitMsg等待提示效果

    //submitForm为form表单 var myMask = new Ext.LoadMask(Ext.getBody(),{msg:"请稍等,正在导入..."}); myMa ...

  4. storm安装配置

    1.修改主机名: vim /etc/sysconfig/network NETWORKING=yes HOSTNAME=MASTER 2.修改IP: 先用ifconfig得到ip信息,将其复制 设置i ...

  5. 获取取并下载tuku的漫画的爬虫

    代码地址如下:http://www.demodashi.com/demo/12842.html 概述 一个简单的爬虫,实现是爬取tuku网站的漫画.并下载到脚本的文件夹中,下载的漫画按照章节名放在各自 ...

  6. lua类库 middleclass学习笔记

    middleclass使在lua中面象对象变的简单 抄了一遍他的示例代码运行着试了试,基本懂了 local class = require 'middleclass' --类的继承 Person = ...

  7. 【转】前端上传组件Plupload

    [转自博客园-无双] html5原生的给我们提供了文件上传的API,Plupload是一款由著名的web编辑器TinyMCE团队开发的上传组件,简单易用且功能强大,我们完全可以使用Plupload来代 ...

  8. csv导出文件中有html

    最近遇到再导出csv文件时,csv文件中包含html代码 一开始以为导出的数据量太大,减少数据后仍然出现html代码,此时想到应该与数据有关,仔细观察csv中的数据,有的单元里面是空值, 对比原始数据 ...

  9. C#中怎样将List&lt;自己定义&gt;转为Json格式 及相关函数-DataContractJsonSerializer

    对C#和.net使用List<自己定义>和Json格式相互转化的方法进行总结 关于JSON的入门介绍见http://www.json.org/ ,或者百度,这里不赘述,只是通过以下的样例会 ...

  10. PE下挂载注册表文件然后清除系统托盘空白图标缓存

    清除了右下角通知栏图标缓存TrayNotify(否则会出现一堆空白图标)清除缓存批处理脚本.bat如何在PE系统环境下清除宿主系统的托盘图标缓存? 清除了右下角通知栏图标缓存TrayNotify(否则 ...