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. git 换行符替换

    https://help.github.com/en/articles/dealing-with-line-endings rm .git/index git reset https://github ...

  2. web网站优化

    没事儿研究一下YAHOO工程师对网站优化给出的策略,对重点部分在这儿做下笔记 -----------------------------------------------我是分割线--------- ...

  3. 关于:Mac下IDEA更换Maven仓库

    一.MAC安装配置maven环境变量 1.下载maven包: 下载链接:

  4. Oracle dbms_random随机函数包

    dbms_random是oracle提供的一个随机函数包,以下是它的一些常用的功能: 1.dbms_random.value 作用:生成一个大于等于0,大于等于1的随机的38位小数,代码如下: sel ...

  5. selenium+Python(文件上传)

    文件上传操作也比较常见功能之一,上传功能没有用到新有方法或函数,上传过程一般要打开一个本地窗口,从窗口选择本地文件添加.所以,一般会卡在如何操作本地窗口添加上传文件只要定位上传按钮,通send_key ...

  6. jQuery validate 设置失去焦点就校验和失去焦点就表单校验是否通过

    js部分 html部分 自定义样式: /*自定义validate覆盖掉了 validate 里面默认的显示样式*/ label.error{ background:url(${pageContext. ...

  7. Java入门系列-17-多态

    这篇文章贯穿游戏中的一些功能带你掌握多态的使用 为什么要使用多态 在一款对战类游戏中(如有雷同纯属巧合),有两个不同的法师英雄:小乔.妲己. 两个法师英雄的都有攻击的方法,小乔的攻击伤害为10,消耗魔 ...

  8. ServiceHelper

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

  9. [转]象棋AI算法(二)

    本文转自:http://blog.csdn.net/u012723995/article/details/47143569 参考文献:http://bbs.blueidea.com/thread-30 ...

  10. PHP学习8——图像处理

    主要内容: 加载GD库 创建图像 绘制点,线,矩形,多边形,椭圆,弧线 绘制文字 通过GD库生成验证码 其实吧,学习图像方法的最大作用,好像就是为了制作验证码. 所以此专题,不如叫做制作验证码. 1. ...