概览

IO是Java中的最重要的一个部分. 其中, java.io是所有编程者都应该掌握的IO方式. 在Java 1.4中, NIO被引入, 它引进了一种新的相对于流模型的新的IO模型, 以为非阻塞IO提供支持. 在Java 7中, NIO2又在NIO的基础上, 引入了对异步IO的支持. 在这篇文章我, 我将对这几种IO方式进行一个比较系统的说明及总结, 同时, 分析每一种IO模型的适用范围.

流IO

流IO是一种最为简洁的IO方式, 几乎所有的编程语言在其标准库中都提供了对流IO的支持, 比如C的FILE, C++的iostream. 同样, 在Java中, 流IO是最为基础也是最为广泛使用的IO方式, 一般来说, 大家对这种方式都比较熟悉了, 总的来说, Java提供Byte输入流/Byte输出流/Char输入流/Char输出流, 同时, 又提供了一系列的Decorator类来在基础流的功能之上, 添加新的功能, 如Buffering.

用下面的四张图可以很好地概括整个流IO的相关类.

输入流

输出流

字符输入流

字符输出流

NIO

一般来说, 流IO表现得很好, 对于大部分的IO场景, 它都能适应. 但是, 由于它的阻塞性, 每一个流的读写都需要占用一个线程. 这意味着, 流IO的可伸缩性很差. 因此, 引入非阻塞IO就再正常不过了. 实际上, NIO就是IO Multiplexing在Java中的实现. IO Multiplexing在系统级语言如C/C++中应用了很长时间. 使用IO Multiplexing, IO的伸缩性大大提高, 使用单个线程, 就可以处理大量的IO对象.

在介绍NIO的非阻塞IO之前, 先大致了解一下NIO提供的IO模型. NIO的概念概念有三个, Buffers/Channels/Selectors. 其中, Channels是输入/输出的管道, 所有的读写操作都需要通过它来完成. Channel读写的粒度是Block, 而不是像流IO一样, 提供一个字节流或者字符流的抽象. 这个Block的抽象即Buffer. 所有的读操作会由Channel将数据读入Buffer, 然后用户来处理Buffer, 所有的写操作需要先将数据填到Buffer中, 再由Channel来消费Buffer中的数据. NIO的第三个核心概念是Selector, 它是一个事件监控器, 我们将它注册我们所感兴趣的IO事件, 并且对其进行Polling, 来确定事件是否发生, 发生则做相应的IO操作. 其中, Selector所监控的对象是Channel, 我们在Selector上声明我们关心哪一个Channel的什么事件, Selector会监控这些Channels, 并在事件发生时通知我们.

现在, 考虑三个问题:

为什么要引入Channel, 直接扩展已有的Stream类不行吗?: 流的抽象已经很完备了, 添加更多的特性与概念只会将流的概念进一步复杂化, API更加难以使用, 这是一种很不好的API设计方式. 因此, NIO引入了一套新的抽象. Do one thing, and do it well.

为什么引入Buffer? 直接用byte数组可以吗?: 实际上肯定是可以的, 但Buffer类提供了更加方便的操作. 同时, Buffer提供了很多性能上的优化.

为什么引入Buffer? 直接读写byte不行吗?: 如果直接操作byte, 性能会很低, 实际上还是需要buffering来提供性能, 与其加一层buffering抽象, 不如直接给用户提供Buffer. 最重要的是, 基于Buffer的IO操作, 某些情况下可以直接映射成系统调用, 性能极高!

NIO支持阻塞与非阻塞两种模式. 阻塞模式下, 实际上与流IO差不多, 非阻塞模式下, Channels与Selector配合, 才是它最大的威力所在.

我们可以大体将Channel分成两类, 一种是支持SelectableChannel(除了FileChannel以外都是, 一般是网络相关的操作.), 另一种与non-SelectableChannel(即FileChannel). 前者可以与Selector一起使用, 提供强伸缩性的IO.

IO VS NIO

考虑IO与NIO的区别. 除了在概念模型的差别, IO与NIO在性能上也会有很大差异. 我们从三个方面来考虑性能问题:

可伸缩性: 流IO的在IO对象数较少及大规模IO的情况下, 表现得很好, 但是当需要处理成百上千的IO对象时, 它的性能会Drop得很快. 相反, NIO在非阻塞模式下(阻塞模式下应该与流IO具有相同的特点, 这是阻塞IO的共性), 即使用Selector, 它可以处理大量的非活跃连接, 是实现C10K的关键技术.

GC: 许多号称高性能的服务器实现, 都以Zero Allocation作为一个重要的功能点. 理想情况上, 如果没有GC的开销, 服务器可以将所有时间花在有效地工作上, 并且保持一个可靠的延迟. 然后GC是不可避免的, Zero Allocation也只能是尽力而为. 而相比较而言, NIO只需要申请一个Buffer, 可以反复使用, 而字符流在这方便表现的就比较差了, 如readLne()这类接口, 需要分配大量临时的String对象.

API抽象层次: 相对而言, 基于Buffer的NIO抽象层次比流IO在低一些. 特别的, 系统调用级别的IO, 都是基于Buffer的. 当使用DirectBuffer时, 某些平台下, OS可以直接将数据复杂到DirectBuffer中, 避免了流IO中, OS将数据复制到OS Buffer后, 又需要向JVM Heap复制地过程. Zero Copy与Zero Allocation都是高性能服务器的重点技术. 特别的, 在使用Channel时, 需要使用DirectBuffer, 因为Channel内部使用的是DirectBuffer. 如果使用HeapBuffer, 则读写时, Channel会申请一个临时的DirectBuffer, 造成性能开销.

Memory Mapping

前面提到, FileChannel不支持非阻塞模式. 那么, 它是不是用处不大呢? 毕竟, NIO与IO相比最大的优势是非阻塞.

NIO中, FileChannel都一些属于自己的特性. 即, Memory Mapping. Memory Mapping是一个比较觉见, 在此不加多说. 无论是在顺序读写, 还是随机读写中, Memory Mapping都能够提供不弱于BufferedInputStream或者RandomAccessFile的性能.

特别强调的是, Memory Mapping可以Map的容量仅与虚拟内存大小有关, 与物理内存大小及JVM堆大小都没有关系. 因此, 在64位平台下, Memory Mapping可以工作得非常好.

ANIO2

聊过非阻塞IO后, 再来看看异步IO. IO方面的概念很多, 阻塞性与异步性是其关键概念. 简单而言, 凡是需要由应用程序将数据读写到应用程序内存中的IO, 都是同步IO, 比如上面的流IO与NIO. 相对的, 凡是由OS来完成读写的, 就是异步IO. 这个说法有些迷惑. 举例而言, 在NIO中, 当应用程序检测到某个Channel有可读数据时, 必须显示发起一个read请求. 而在异步IO中, 应用程序仅仅需要告诉OS, 我需要什么数据, 并提供给OS一个Buffer和一个回调. OS会自己检测Channel的可读性, 但其发起其可读, 会自动将数据复制到Buffer中, 并通知应用程序任务完成. 异步IO的典型实现是NodeJS及Boost.ASIO. 显然, 由于将任务进一步下发到了OS, 应用程序的可伸缩性及性能会大大增强. 并且, 比起非阻塞的NIO, 异步IO编程更加容易一些, 性能也基本上总是优于它的.

NIO2最大的改进是引入了四个异步Channel, 用于支持异步读写. 同时, 它还增加了对文件系统和文件属性的支持, 提供了WatchService/FileVisitor这些高级功能.

原文地址:https://www.jianshu.com/p/07d3d421a877

Java IO NIO NIO2相关推荐

  1. IO NIO NIO2(AIO) 概述

    一.概述 在我们学习Java的IO流之前,我们都要了解几个关键词 同步与异步(synchronous/asynchronous):同步是一种可靠的有序运行机制,当我们进行同步操作时,后续的任务是等待当 ...

  2. java io nio socket_通过socket编程掌握IO流 —— NIO

    一.本次目标 改造server,采用NIO读取client信息: 改造client,亦采用NIO发送消息,与之前不同的BIO形成对比: 二.编码 1.新建byte数组拼接公共类 主要用作在channe ...

  3. java io nio aio_Java IO、NIO、AIO知识总结

    本文主要讲述下自己对IO的理解,对IO的用法和细则可能没有顾虑到. 本文的理解基于以下几篇文章,他们对各自部分都讲的很细,对我理解IO提供了很大帮助. 该文主要讲解了Java IO的类体系以及他们各自 ...

  4. Java IO/NIO教程

    Java IO教程 http://tutorials.jenkov.com/java-io/index.html Java NIO教程 英文版: http://tutorials.jenkov.com ...

  5. 以点破面——JAVA IO/NIO

    JAVA IO 阻塞IO模型 最传统的一种 IO 模型,即在读写数据过程中会发生阻塞现象.当用户线程发出 IO 请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞 ...

  6. java ----IO/NIO/AIO

    1 使用File API里有很多关于File的使用方法: 案例:向磁盘创建文件 创建多级文件夹: 需要加s 把D盘的文件移动到C盘并且改为a.zip 2 文件遍历案例 找某盘下,大小为xxmb,后缀为 ...

  7. java io nio pio_Netty之BIO(同步阻塞IO)、PIO(偽異步阻塞IO)、NIO(異步非阻塞IO)、AIO(異步非阻塞IO)、Netty...

    學習書籍:Netty權威指南 多種IO方式的比較: 1.BIO(同步阻塞IO) 使用ServerSocket綁定IP地址和監聽端口,客戶端發起連接,通過三次握手建立連接,用socket來進行通信,通過 ...

  8. Java IO/NIO

    阻塞IO 最传统的一种IO模型,即在读写数据过程中会发生阻塞现象.当用户线程发出IO 请求之后,内 核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用 户线程交出CP ...

  9. JAVA IO : BIO NIO AIO

    JAVA IO : BIO NIO AIO 同步异步.阻塞非阻塞概念 同步与异步 阻塞与非阻塞 IO VS NIO VS AIO 面向流与面向缓冲 阻塞与非阻塞IO BIO.NIO.AIO的JAVA实 ...

最新文章

  1. BLE-NRF51822-实现简单扫描器
  2. POJ 1486 Sorting Slides(二分图完全匹配必须边)题解
  3. BM16 删除有序链表中重复的元素-II
  4. Python之Time模块
  5. 构建线性表的c语言代码,数据结构严蔚敏C语言版—线性表顺序存储结构(顺序表)C语言实现相关代码...
  6. 腾讯云服务器配置ftp~
  7. 结构体(struct)与类(class)
  8. java.lang.SecurityException: class “org.bouncycastle.asn1.DERObject“‘s signer information does not m
  9. Educational Codeforces Round 77 D.A Game with Traps(二分+差分+前缀和)
  10. CurvySplines基础
  11. 版本控制gitlab
  12. 5G牌照都发完了,那些传说中的5G手机Ready了吗?
  13. eclipse背景设置什么颜色缓解眼睛疲劳之一
  14. 剑指Offer_46 把数字翻译成字符串
  15. 使用AutoHotKey将多行内容转成单行并翻译或获取中文拼音
  16. DDNS的NAT穿越问题
  17. 设计模式之CS和BS结构的区别
  18. 各种图论模型及其解答
  19. 均衡负载集群(LBC)-2
  20. curl php 宝塔 开启_宝塔安装php失败

热门文章

  1. 安装ffmpeg win10教程
  2. CAPL 无法处理 xlsx 表格,Python老大哥曲线助攻
  3. leetcode切绳子
  4. java 编程思想 并发_java编程思想-java中的并发(一)
  5. Selenium私房菜系列
  6. Java中的图形界面编程-GUI
  7. 2021全球与中国车辆线控转向系统市场现状及未来发展趋势
  8. 纪念品分组java_纪念品分组 (Java代码)
  9. 计算机如何增加网络地址,如何添加网络打印机到电脑
  10. 简单假币问题以及复杂假币问题