在研究Java NIO和IO API时,很快就会想到一个问题:

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

在本文中,我将尝试阐明Java NIO和IO之间的区别,它们的用例以及它们如何影响代码的设计。 ###Java NIO和IO之间的主要区别 下表总结了Java NIO和IO之间的主要区别。 我将在表格后面的部分详细介绍每个区别。

IO NIO
面向流 利用缓冲区
阻塞IO 非阻塞IO
Selectors

###流导向vs缓冲导向 Java NIO和IO之间的第一大区别是IO是面向流的,其中NIO是面向缓冲区的。 那么,这是什么意思?

面向流的Java IO意味着您一次从流中读取一个或多个字节。 你所做的读字节取决于你。 他们没有被缓存在任何地方。 而且,您不能前后移动数据流。 如果您需要前后移动从流中读取的数据,则需要先将其缓存在缓冲区中。

Java NIO的面向缓冲区的方法略有不同。 数据被读入一个缓冲区,稍后进行处理。 您可以根据需要前后移动缓冲区。 这给你在处理过程中更多的灵活性。 但是,您还需要检查缓冲区是否包含您需要的所有数据,以便对其进行全面处理。 而且,您需要确保在将更多数据读入缓冲区时,不会覆盖尚未处理的缓冲区中的数据。 ###阻塞vs非阻塞IO Java IO的各种流都被阻塞。 这意味着,当一个线程调用一个read()或write()时,该线程被阻塞,直到有一些数据要读取,或者数据被完全写入。 线程在此期间不能做其他事情。

Java NIO的非阻塞模式使得线程可以请求从一个通道读取数据,并且只获取当前可用的数据,或者根本没有任何数据可用。 线程可以继续使用别的东西,而不是在数据可用于读取之前保持阻塞状态。

无阻塞写入也是如此。 一个线程可以请求将一些数据写入一个通道,但不要等待它被完全写入。 线程然后可以继续,同时做其他事情。

线程在没有被IO阻塞的情况下花费空闲时间,通常是在其他通道上同时执行IO。 也就是说,一个线程现在可以管理多个输入输出通道。

###Selectors Java NIO的选择器允许单线程监视多个输入通道。 您可以使用选择器注册多个通道,然后使用单个线程“选择”可用于处理的输入通道,或者选择准备写入的通道。 这个选择器机制使单个线程可以轻松管理多个通道。 ###NIO和IO如何影响应用程序设计 无论您选择NIO还是IO作为您的IO工具包,都可能会影响您应用程序设计的以下方面:

  1. API调用NIO或IO类。
  2. 数据的处理。
  3. 用于处理数据的线程数。 ###API调用 当然,使用NIO时的API调用看起来不同于使用IO时的调用。 这并不奇怪。 而不只是从例如数据字节读取字节。 一个InputStream,数据必须首先被读入一个缓冲区,然后从那里被处理。 ###数据处理 当使用纯粹的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 bytesRead = inChannel.read(buffer);
复制代码

注意从通道读取字节到ByteBuffer的第二行。 当该方法调用返回时,您不知道所需的所有数据是否在缓冲区内。 所有你知道的是,缓冲区包含一些字节。 这使得处理有点困难。

想象一下,如果在第一次读取(缓冲区)调用之后,所有读入缓冲区的内容都是半行。 例如,"Name: An"。 你能处理这些数据吗? 不是真的。 你需要等待,直到完整的一行数据已经进入缓冲区,才有意义处理任何数据。

那么如何知道缓冲区中是否包含足够的数据才能处理? 那么,你没有。 唯一的办法就是查看缓冲区中的数据。 结果是,您可能需要多次检查缓冲区中的数据,才能知道所有数据是否在内部。 这既是低效的,而且在程序设计方面可能变得混乱。 例如:

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

bufferFull()方法必须跟踪有多少数据被读入缓冲区,并根据缓冲区是否已满而返回true或false。 换句话说,如果缓冲区准备好处理,则认为已满。

bufferFull()方法扫描缓冲区,但必须保持缓冲区处于与调用bufferFull()方法之前相同的状态。 否则,读入缓冲区的下一个数据可能无法在正确的位置读入。 这不是不可能的,但这是另一个需要注意的问题。

如果缓冲区已满,可以进行处理。 如果它没有满,那么你可能能够部分处理任何数据,如果这在你的特定情况下是有意义的。 在许多情况下,它不是。

图中显示了is-data-in-buffer-ready循环:

###概要 NIO允许您仅使用一个(或几个)线程来管理多个通道(网络连接或文件),但代价是解析数据可能比从阻塞流读取数据时要复杂一些。

如果你需要管理数以千计的同时打开的连接,每一个只发送一点点的数据,例如聊天服务器,在NIO中实现服务器可能是一个优势。 同样,如果你需要保持与其他计算机的大量开放连接,例如 在P2P网络中,使用单个线程来管理所有出站连接可能是一个优势。 这一个线程,多个连接设计如下图所示:

如果您的连接带宽非常高,一次发送大量数据,那么传统的IO服务器实现可能是最合适的。 该图说明了一个经典的IO服务器设计:

Java NIO (十四)NIO 和 IO 的区别和适用场景分析相关推荐

  1. Java第十四课——相声和群口相声

    Java第十四课--相声和群口相声 Java第十四课--相声和群口相声 一.聊天界面优化 二.增加发送内容的样式 三.群聊雏形 相声,我们知道有一个逗哏一个捧哏,也就是一唱一和,也就相当于双向的交流. ...

  2. 理解NIO和IO的区别和应用场景,这一篇就够了

    Java中的NIO和IO的区别 IO IO(Input/Output)是Java中用于处理输入输出的标准库.在IO中,数据的读取和写入都是通过字节流(InputStream/OutputStream) ...

  3. java第十四章上机四客户类_java语言程序设计教学大纲.doc

    java语言程序设计教学大纲.doc 还剩 5页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,喜欢就下载吧,价低环保! 内容要点: 第六章 结构控制 2 2第七章 数组 2第八章 字符串 ...

  4. java 常用集合list与Set、Map区别及适用场景总结

    转载请备注出自于:http://blog.csdn.net/qq_22118507/article/details/51576319   list与Set.Map区别及适用场景 1.List,Set都 ...

  5. 四张图,读懂 BIO、NIO、AIO、多路复用 IO 的区别

    作者:扛麻袋的少年 blog.csdn.net/lzb348110175/article/details/98941378 学习之前,我们先来了解一下IO模型: ①同步阻塞IO(Blocking IO ...

  6. 四图,读懂 BIO、NIO、AIO、多路复用 IO 的区别

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源:blog.csdn.net/lzb348110175 ...

  7. 图解BIO、NIO、AIO、多路复用IO的区别

    作者:扛麻袋的少年 blog.csdn.net/lzb348110175/article/details/98941378 学习之前,我们先来了解一下IO模型: ①同步阻塞IO(Blocking IO ...

  8. 学习Java第二十四天

    目录 一.网络编程 1.概述 2.三要素 二.IP地址 1.分类 2.方法 三.UDP 1.通信原理 2.发送数据 3.接收数据 四.TCP 1.原理 2.发送数据 2.接收数据 一.网络编程 1.概 ...

  9. 皮皮安学Java第二十四天

    写在前面 没啥好说的,上总结 今日与昨日所学 2.2使用throws 如果是一个方法可能会产生某种异常,但不知道如何处理这种异常,此时可以声明该方法抛出异常,表明该方法不对这种异常进行处理,而由该方法 ...

最新文章

  1. anaconda降级python失败_如何降级Python版本安装spyder?
  2. 【Github】怎么在README.md中添加图片?
  3. uva 1463 - Largest Empty Circle on a Segment(二分+三分+几何)
  4. 区块链技术指南之分布式系统核心问题
  5. 微信公众号 语音转文字api_快速上手——微信公众号开发接入
  6. 小程序无法获取用户头像的原因
  7. 网络编程实验综合报告
  8. next主题美化——背景图片、页面透明化、阴影、圆角、动画
  9. 云计算-平台架构-开源-OpenStack
  10. 安装torch 时,bash install-deps错误
  11. 解决Safari使用谷歌搜索引擎需要二次确认
  12. java商品详情查询_商品详情页面的显示
  13. ⑦企业级zabbix监控 微信报警、邮箱报警、钉钉报警、全网最细
  14. 云计算、大数据和人工智的区别和联系
  15. 腾讯太极文生图大模型,带你一起感受祖国大好河山
  16. 推荐算法(一)——音乐歌单智能推荐
  17. 金蝶k3服务器物理内存过高,物理内存过高的解决办法
  18. c语言转义字符(c语言转义字符是什么意思)
  19. java读取qq邮箱_通过java给qq邮箱发送信息
  20. BGP路由协议实验配置命令

热门文章

  1. 关闭 Pycharm 更新提示
  2. Caused by: java.lang.IllegalStateException: StandardEngine[Tomcat].StandardHost[localhost].TomcatEmb
  3. c语言标识符的文法表示,第三章文法和语法[lly]3.ppt
  4. flux react php,Vue的Flux框架之Vuex状态管理器
  5. ios 不被遮挡 阴影_为何你没见到日环食?你不知道的天象常识原来还有这么多 | 返朴...
  6. leetcode360. 有序转化数组
  7. 数组精选题目三连(6)
  8. 机器学习知识总结系列-机器学习中的优化算法总结(1-4)
  9. 入夏多吃这些“杀菌菜”
  10. css background-attachment:fixed 固定背景、不随内容一起滚动