Java NIO(1):迟迟登场的NIO

Java NIO的出现  

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

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

  Java须要运行于虚拟机(即JVM)之上,为了保证Java字节码在各类JVM部署平台上运行效果一致,做些妥协是必须的。既然须要通用于不一样的操做系统平台,那么,某种程度上就必须选择各类平台都接受的处理方案。这也就形成了Java不能发挥各类平台的特性和优化的地方。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的缓冲区则否则,对缓冲区的移进/移出操做是由底层操做系统来实现的。jsp

  一般一次缓冲区操做是这样的:某个进程须要进行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代码实现复杂,不易理解。选择与否全看使用的场景,这点就看使用者的权衡了。

相关文章
相关标签/搜索