在学习Java NIO和IO的API时,经常会出现以下疑问?

什么时候我应该用IO,什么时候我应该用NIO?

在这篇文章中我将发表我关于NIO与IO的区别的观点,它们的使用案例,以及它们如何影响你代码的设计。

Java NIO与IO的主要区别

IO NIO
面向流 面向缓冲
阻塞IO 非阻塞IO
无Selector Selectors

面向流与面向缓冲

Java NIO与IO最大的不同之处在IO是面向流的,而NIO是面向缓冲的。但是,这意味着什么呢?

Java IO面向流意味着你一次会从流中读取一个或多个字节。对于读取到的字节怎么处理由你自己决定。这些字节是不会被缓存的。更一步,流中的数据并不能前面移动。如果需要前后移动数据,需要先将数据进行缓存。

而Java NIO面向缓存的方式稍有不同。需要后续处理的数据是先放到缓存中的。可以在缓存中前后移动。这使得数据处理变得更加灵活。然而,你需要检查缓存里是否包含了需要处理的完整数据。并且,也需要保证没有处理过的数据在写入新数据时不会被覆盖。

阻塞与非阻塞

Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

Selector

Java NIO Selector允许一个线程来控制多个输入通道。可以用一个Selector注册多个Channle。然后,用一个线程来选择已经准备好数据处理的Channel或都那些准备好写的Channel。选择器的机制使得用一个线程来控制多个Channel变得非常容易。

NIO和IO如何影响应用程序的设计

无论你选择NIO或IO工具箱,可能会影响你应用程序的以下几个方面:

  1. 对NIO或IO类的API调用。
  2. 数据处理。
  3. 用来处理数据的线程数。

API调用

当然,在使用IO时,NIO与IO的API调用有点不同。这一点也不奇怪。并不是直接从InputStream中直接读取数据,NIO必须先将数据读入到缓存中,再进行后续处理。

数据处理

使用纯粹的NIO设计相较IO设计,数据处理也受到影响。

在IO设计时,数据是从InputStream或Reader中读取的。假设你正在处理基于文本的数据,像这样:

Name: Anna
Age: 25
Email: anna@mailserver.com
Phone: 1234567890
复制代码

文本行的流可以像这样处理:

InputStream input = ... ; // get the InputStream from the client socketBufferedReader reader = new BufferedReader(new InputStreamReader(input));String nameLine   = reader.readLine();
String ageLine    = reader.readLine();
String emailLine  = reader.readLine();
String phoneLine  = reader.readLine();
复制代码

请注意处理状态由程序执行多久决定。换句话说,一旦reader.readLine()方法返回,你就知道肯定文本行就已读完, readline()阻塞直到整行读完,这就是原因。你也知道此行包含名称;同样,第二个readline()调用返回的时候,你知道这行包含年龄等。 正如你可以看到,该处理程序仅在有新数据读入时运行,并知道每步的数据是什么。一旦正在运行的线程已处理过读入的某些数据,该线程不会再回退数据(大多如此)。下图也说明了这条原则:

在NIO实现中这将会变得有点不一样,下面是一个简单的例子。

ByteBuffer buffer = ByteBuffer.allocate(48);
int byteRead = inChannel.read(buf);
复制代码

注意到将Channel中的数据读入到Buffer中的第二行。当那个方法返回时,其实并不知道所需要的数据是否都已经写入到Buffer中了。仅仅知道的是一些数据已经写入到Buffer中了。这使得数据处理变得有点麻烦。

想像一下,当调用完第一个read(buufer)方法时,仅有半行的数据被读入到Buffer中。例如,“Name:An”。你量否可以处理这个数据?并不能。在有效处理数据之前必须等到至少有一行数据被读入到Buffer中才行。

所以,如何能够知道uffer中包含了能够有效处理的足够的数据呢?其实并不能。唯一的方法是检查Buffer中的数据。这个结果是,你必须多次检查Buffer中的数据来判断数据是否完整。不仅效率低下,而且可以使程序设计方案杂乱不堪。例如:

ByteBuffer buffer = ByteBuffer.allocate(48);int bytesRead = inChannel.read(buffer);while(! bufferFull(bytesRead) ) {bytesRead = inChannel.read(buffer);
}
复制代码

bufferFull()方法需要跟踪读入buffer中的字节数并根据buffer是否满了来返回true或false。换句话说,如果buffer已经准备好处理了,它将认为是full的。

bufferFull()方法扫描缓冲区,但必须保持在bufferFull()方法被调用之前状态相同。如果没有,下一个读入缓冲区的数据可能无法读到正确的位置。这是不可能的,但却是需要注意的又一问题。

如果缓冲区已满,它可以被处理。如果它不满,并且在你的实际案例中有意义,你或许能处理其中的部分数据。但是许多情况下并非如此。下图展示了“缓冲区数据循环就绪”:

总结

NIO可以让你仅使用一个或少量的线程来管理多个通道(网络或文件)。但是分析数据会比阻塞的IO流更加复杂。

如果你需要同时管理成千上万个连接,并且这个连接只发送少量的数据。比如,一个用NIO方式实现的聊天服务器将变得非常有优势。类似的,如果需要跟其他计算机保持大量的连接,如P2P网络。使用一个线程来管道外部连接可以也是一个优势。单个线条,多个连接的方式如下图所示:

如果只有少量连接,但每个连接都有占用大量的带宽,每次需要发送大量的数据,也许采用阻塞的IO将会更加适合。下图展示一个IO服务器的设计:

14 Java NIO vs IO-翻译相关推荐

  1. 史上讲的最好的Java NIO与IO的区别与应用

    如果下面的内容看的不太懂,直接看最后的摘要和总结. 在研究Java NIO和IO API时,很快就会发现一个问题: 我什么时候应该使用IO,什么时候应该使用NIO? 在本文中,我将尝试阐明Java N ...

  2. Java NIO与IO的区别和比较

    Java NIO与IO的区别和比较 导读 J2SE1.4以上版本中发布了全新的I/O类库.本文将通过一些实例来简单介绍NIO库提供的一些新特性:非阻塞I/O,字符转换,缓冲以及通道. 一. 介绍NIO ...

  3. Java NIO系列教程(十二) Java NIO与IO

    原文地址:http://tutorials.jenkov.com/java-nio/nio-vs-io.html 作者:Jakob Jenkov   译者:郭蕾    校对:方腾飞 当学习了Java ...

  4. Java NIO和IO的主要区别

    2019独角兽企业重金招聘Python工程师标准>>> Java NIO和IO的主要区别如下: 1.NIO 的创建目的是为了让 Java 程序员可以实现高速 I/O 而无需编写自定义 ...

  5. Java NIO与IO比较总结

    在学习标准IO相关接口和NIO接口时,我们常常面临一个问题:什么时候应该使用IO接口?什么时候应该使用NIO接口? 这里我们将对比较Java NIO 和 IO的区别,他们的使用场景,如何使用他们编写高 ...

  6. Java NIO与IO

    当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们如何影响您的代 ...

  7. Java NIO:IO与NIO的区别

    一.概念 NIO即New IO,这个库是在JDK1.4中才引入的.NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多.在Java API中提供了两套N ...

  8. Java NIO与IO的差别和比較

    导读 J2SE1.4以上版本号中公布了全新的I/O类库.本文将通过一些实例来简介NIO库提供的一些新特性:非堵塞I/O,字符转换,缓冲以及通道. 一. 介绍NIO NIO包(java.nio.*)引入 ...

  9. 详解Java NIO,IO与NIO的区别

    一.概念 NIO即New IO,这个库是在JDK1.4中才引入的.NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多.在Java API中提供了两套N ...

最新文章

  1. C# 4.0新特性——Optional Parameters
  2. openstack domain serverID connect uri
  3. 最短路径Dijkstra讲解,工具包使用 python
  4. java 接口 this参数_Java BiFunction 接口实例
  5. Bzoj4822 [Cqoi2017]老C的任务
  6. centos 6.5 安装qt5.2
  7. VScode安装并设置SVN插件
  8. 二叉树非递归程序c语言,二叉树非递归遍历C语言实现
  9. Excel表Ctrl+v和Ctrl shift+v有什么区别_朴素的办公神器——excel
  10. Windows对话框
  11. 对视图有时为什么使用select top 100 percent 而不使用 select 呢
  12. C++ - std::srand
  13. Dynamo For Revit: List 连缀 和 Level
  14. STM32中断中调用OLED显示出现OLED花屏
  15. Linux中断分析2
  16. 2022年登高架设操作证考试题及在线模拟考试
  17. 嵌入式三级知识点分类
  18. ignore在mysql中什么意思_INSERTIGNORE与INSERTINTO的区别_MySQL
  19. 数组中元素旋转移位的三种实现方法 --By LXW
  20. Python全栈(八)Flask项目实战之6.前台注册功能开发

热门文章

  1. 剑指offer反转链表(C++实现|测试用例|迭代法和递归法)
  2. [BUUCTF-pwn]——bjdctf_2020_babyrop
  3. C语言能否写windows应用程序,C语言能写windows的窗口吗?
  4. oracle的into的含义,请问在oracle 中select into是什么意思?
  5. java 短信猫发送短信的方法
  6. 理解变量字符的截取功能
  7. 不会提示是否关闭浏览器 IE6、IE7、FF通用代码
  8. 针对集合中的某个字段对集合中的对象进行排序
  9. SQL Server 2008 R2 中不能删除复制(replication) 的解决方法
  10. 转载 cFos vs cFosSpeed