JAVA NIO vs IO

当我们学习了Java NIO和IO后,我们很快就会思考一个问题:

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

在下文中我会尝试用例子阐述java NIO 和IO的区别,以及它们对你的设计会有什么影响

Java NIO和IO的主要区别

IO NIO
面向Stream 面向Buffer
阻塞IO 非阻塞IO
  Selectors

 

面向Stream和面向Buffer

Java NIO和IO之间最大的区别是IO是面向流(Stream)的,NIO是面向块(buffer)的,所以,这意味着什么?

面向流意味着从流中一次可以读取一个或多个字节,拿到读取的这些做什么你说了算,这里没有任何缓存(这里指的是使用流没有任何缓存,接收或者发送的数据是缓存到操作系统中的,流就像一根水管从操作系统的缓存中读取数据)而且只能顺序从流中读取数据,如果需要跳过一些字节或者再读取已经读过的字节,你必须将从流中读取的数据先缓存起来

面向块的处理方式有些不同,数据是先被 读/写到buffer中的,根据需要你可以控制读取什么位置的数据。这在处理的过程中给用户多了一些灵活性然而,你需要额外做的工作是检查你需要的数据是否已经全部到了buffer中,你还需要保证当有更多的数据进入buffer中时,buffer中未处理的数据不会被覆盖

阻塞IO和非阻塞IO

所有的Java IO流都是阻塞的,这意味着,当一条线程执行read()或者write()方法时,这条线程会一直阻塞知道读取到了一些数据或者要写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情

java NIO的非阻塞模式(Java NIO有阻塞模式和非阻塞模式,阻塞模式的NIO除了使用Buffer存储数据外和IO基本没有区别)允许一条线程从channel中读取数据,通过返回值来判断buffer中是否有数据,如果没有数据,NIO不会阻塞,因为不阻塞这条线程就可以去做其他的事情,过一段时间再回来判断一下有没有数据

NIO的写也是一样的,一条线程将buffer中的数据写入channel,它不会等待数据全部写完才会返回,而是调用完write()方法就会继续向下执行

Selectors

Java NIO的selectors允许一条线程去监控多个channels的输入,你可以向一个selector上注册多个channel,然后调用selector的select()方法判断是否有新的连接进来或者已经在selector上注册时channel是否有数据进入。selector的机制让一个线程管理多个channel变得简单。


NIO和IO对应用的设计有何影响

选择使用NIO还是IO做你的IO工具对应用主要有以下几个方面的影响

1、使用IO和NIO的API是不同的(废话)

2、处理数据的方式

3、处理数据所用到的线程数

处理数据的方式

在IO的设计里,要一个字节一个字节从InputStream 或者Reader中读取数据,想象你正在处理一个向下面的基于行分割的流

  1.  
    Name:Anna
  2.  
    Age: 25
  3.  
    Email: anna@mailserver.com
  4.  
    Phone:1234567890

处理文本行的流的代码应该向下面这样

  1. InputStream input = ... ; // get the InputStream from the client socket
  2.  
  3. BufferedReader reader = new BufferedReader(new InputStreamReader(input));
  4.  
  5. String nameLine = reader.readLine();
  6. String ageLine = reader.readLine();
  7. String emailLine = reader.readLine();
  8. String phoneLine = reader.readLine();

注意,一旦reader.readLine()方法返回,你就可以确定整行已经被读取,readLine()阻塞知道一整行都被读取

NIO的实现会有一些不同,下面是一个简单的例子

  1. ByteBuffer buffer = ByteBuffer.allocate(48);
  2.  
  3. int bytesRead = inChannel.read(buffer);

注意第二行从channel中读取数据到ByteBuffer,当这个方法返回你不知道是否你需要的所有数据都被读到buffer了,你所知道的一切就是有一些数据被读到了buffer中,但是你并不知道具体有多少数据,这使程序的处理变得稍微有些困难

想象一下,调用了read(buffer)方法后,只有半行数据被读进了buffer,例如:“Name: An”,你能现在就处理数据吗?当然不能。你需要等待直到至少一整行数据被读到buffer中,在这之前确保程序不要处理buffer中的数据

你如何知道buffer中是否有足够的数据可以被处理呢?你不知道,唯一的方法就是检查buffer中的数据。可能你会进行几次无效的检查(检查了几次数据都不够进行处理),这会令程序设计变得比较混乱复杂

  1. ByteBuffer buffer = ByteBuffer.allocate(48);
  2.  
  3. int bytesRead = inChannel.read(buffer);
  4.  
  5. while(! bufferFull(bytesRead) ) {
  6. bytesRead = inChannel.read(buffer);
  7. }

bufferFull方法负责检查有多少数据被读到了buffer中,根据返回值是true还是false来判断数据是否够进行处理。bufferFull方法扫描buffer但不能改变buffer的内部状态

is-data-in-buffer-ready 循环柱状图如下

总结

NIO允许你用一个单独的线程或几个线程管理很多个channels(网络的或者文件的),代价是程序的处理和处理IO相比更加复杂

如果你需要同时管理成千上万的连接,但是每个连接只发送少量数据,例如一个聊天服务器,用NIO实现会更好一些,相似的,如果你需要保持很多个到其他电脑的连接,例如P2P网络,用一个单独的线程来管理所有出口连接是比较合适的

 


如果你只有少量的连接但是每个连接都占有很高的带宽,同时发送很多数据,传统的IO会更适合


NIO图解

 

java面试题之----IO与NIO的区别的更多相关文章

  1. Java NIO:IO与NIO的区别 -阿里面试题

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

  2. java的nio之:java的nio系列教程之java的io和nio的区别

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

  3. 面试题_66_to_75_Java IO 和 NIO 的面试题

    IO 是 Java 面试中一个非常重要的点.你应该很好掌握 Java IO,NIO,NIO2 以及与操作系统,磁盘 IO 相关的基础知识.下面是 Java IO 中经常问的问题. 66)在我 Java ...

  4. Java NIO:IO与NIO的区别

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

  5. 面试题思考:IO 和 NIO的区别,NIO优点

    面试时答: IO是面向流的,NIO是面向缓冲区的 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方: NIO则能前后移动流中的数据,因为是面向缓冲区的 ...

  6. netty1---传统IO和NIO的区别

    传统IO: package OIO; import java.io.IOException; import java.io.InputStream; import java.net.ServerSoc ...

  7. 【NIO】IO与NIO的区别

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

  8. java IO和NIO 的区别

    Java NIO和IO的主要区别 下表总结了Java NIO和IO之间的主要差别. IO                NIO 面向流            面向缓冲 阻塞IO           非 ...

  9. java 21 - 15 新IO流 NIO

    1:JDK4  新IO要了解的类 Buffer(缓冲),Channer(通道) 2:JDK7  要了解的新IO类 Path:与平台无关的路径. Paths:包含了返回Path的静态方法. public ...

随机推荐

  1. javascript 正则表达式校验方式写法

    if(/[0-9]/.test(value)){return true; } if(/[a-z]/.test(value)){return true; } if(/[A-Z]/.test(value) ...

  2. 数据备份及恢复(mongodump/mongorestore)

    说明 1.mongodump创建高保真的BSON文件,mongorestore可以用其恢复数据库.对于小型数据库的备份和恢复,这两个工具非常简单和高效,但对于大型数据库的备份并不理想.2.mongod ...

  3. fastclick源码分析

    https://www.cnblogs.com/diver-blogs/p/5657323.html  地址 fastclick.js源码解读分析 阅读优秀的js插件和库源码,可以加深我们对web开发 ...

  4. npm全局安装和局部文件安装区别

    全局安装往往是安装一个工具,他不是安装在一个文件夹下,而是安装在某个全局环境下,如目前我的安装路径是: C:\Users\cvter\AppData\Roaming\npm 在这里,我们可以看到所有全 ...

  5. 【Qt开发】01-第一个Qt程序Hello World!

    一:说在前头 我的第一份工作是做生产工具,当时用的MFC,IDE是VC6.0,现在想想真是古董级别,10年至今,微软也一直没有对MFC进行升级, 冥冥中感觉微软自己都放弃MFC了,市场上貌似MFC的岗 ...

  6. 【CSS】 布局之多列等高

    这两天看了不少文章,对于css布局多了一些理解,现在来总结下. 我们来写一个最普遍的Top.Left.Content.Right.Foot布局. 第一步:自然是写一个坯子 <!DOCTYPE H ...

  7. Android OpenGL教程-第三课【转】

    第三课 给多边形上色: 作为第二课的扩展,我将叫你如何使用颜色.你将理解两种着色模式,在左图中,三角形用的是光滑着色,四边形用的是平面着色. 这次增加的代码不算多. 增加一个color的buffer ...

  8. Delphi下OpenGL2d绘图(02)-画点

    一.前言 图形的绘制可以使用glBegin().glEnd()之间完成,绘制的框架代码可以使用 Delphi下OpenGL2d绘图(01)-初始化 中的代码.修改的部份为 Draw 函数的内容. 二. ...

  9. ServiceHelper

    public class ServiceHelper { private static string _baseUrl = $@"http://{Config.Instance.MesSer ...

  10. sql server存储过程中SELECT 与 SET 对变量赋值的区别 转自Theo

    SQL Server 中对已经定义的变量赋值的方式用两种,分别是 SET 和 SELECT. 对于这两种方式的区别,SQL Server 联机丛书中已经有详细的说明,但很多时候我们 并没有注意,其实这 ...