浅谈Java中IO和NIO的本质和区别
作者:flydean 发布时间:2023-11-01 01:44:08
IO的本质
IO的作用就是从外部系统读取数据到java程序中,或者把java程序中输出的数据写回到外部系统。这里的外部系统可能是磁盘,网络流等等。
因为对所有的外部数据的处理都是由操作系统内核来实现的,对于java应用程序来说,只是调用操作系统中相应的接口方法,从而和外部数据进行交互。
所有IO的本质就是对Buffer的处理,我们把数据放入Buffer供系统写入外部数据,或者从系统Buffer中读取从外部系统中读取的数据。如下图所示:
用户空间也就是我们自己的java程序有一个Buffer,系统空间也有一个buffer。所以会出现系统空间缓存数据的情况,这种情况下系统空间将会直接返回Buffer中的数据,提升读取速度。
DMA和虚拟地址空间
在继续讲解之前,我们先讲解两个操作系统中的基本概念,方便后面我们对IO的理解。
现代操作系统都有一个叫做DMA(Direct memory access)的组件。这个组件是做什么的呢?
一般来说对内存的读写都是要交给CPU来完成的,在没有DMA的情况下,如果程序进行IO操作,那么所有的CPU时间都会被占用,CPU没法去响应其他的任务,只能等待IO执行完成。这在现代应用程序中是无法想象的。
如果使用DMA,则CPU可以把IO操作转交给其他的操作系统组件,比如数据管理器来操作,只有当数据管理器操作完毕之后,才会通知CPU该IO操作完成。现代操作系统基本上都实现了DMA。
虚拟地址空间也叫做(Virtual address space),为了不同程序的互相隔离和保证程序中地址的确定性,现代计算机系统引入了虚拟地址空间的概念。简单点讲可以看做是跟实际物理地址的映射,通过使用分段或者分页的技术,将实际的物理地址映射到虚拟地址空间。
对于上面的IO的基本流程图中,我们可以将系统空间的buffer和用户空间的buffer同时映射到虚拟地址空间的同一个地方。这样就省略了从系统空间拷贝到用户空间的步骤。速度会更快。
同时为了解决虚拟空间比物理内存空间大的问题,现代计算机技术一般都是用了分页技术。
分页技术就是将虚拟空间分为很多个page,只有在需要用到的时候才为该page分配到物理内存的映射,这样物理内存实际上可以看做虚拟空间地址的缓存。
虚拟空间地址分页对IO的影响就在于,IO的操作也是基于page来的。
比较常用的page大小有:1,024, 2,048, 和 4,096 bytes。
IO的分类
IO可以分为File/Block IO和Stream I/O两类。
对于File/Block IO来说,数据是存储在disk中,而disk是由filesystem来进行管理的。我们可以通过filesystem来定义file的名字,路径,文件属性等内容。
filesystem通过把数据划分成为一个个的data blocks来进行管理。有些blocks存储着文件的元数据,有些block存储着真正的数据。
最后filesystem在处理数据的过程中,也进行了分页。filesystem的分页大小可以跟内存分页的大小一致,或者是它的倍数,比如 2,048 或者 8,192 bytes等。
并不是所有的数据都是以block的形式存在的,我们还有一类IO叫做stream IO。
stream IO就像是管道流,里面的数据是序列被消费的。
IO和NIO的区别
java1.0中的IO是流式IO,它只能一个字节一个字节的处理数据,所以IO也叫做Stream IO。
而NIO是为了提升IO的效率而生的,它是以Block的方式来读取数据的。
Stream IO中,input输入一个字节,output就输出一个字节,因为是Stream,所以可以加上过滤器或者过滤器链,可以想想一下web框架中的filter chain。在Stream IO中,数据只能处理一次,你不能在Stream中回退数据。
在Block IO中,数据是以block的形式来被处理的,因此其处理速度要比Stream IO快,同时可以回退处理数据。但是你需要自己处理buffer,所以复杂程度要比Stream IO高。
一般来说Stream IO是阻塞型IO,当线程进行读或者写操作的时候,线程会被阻塞。
而NIO一般来说是非阻塞的,也就是说在进行读或者写的过程中可以去做其他的操作,而读或者写操作执行完毕之后会通知NIO操作的完成。
在IO中,主要分为DataOutPut和DataInput,分别对应IO的out和in。
DataOutPut有三大类,分别是Writer,OutputStream和ObjectOutput。
看下他们中的继承关系:
DataInput也有三大类,分别是ObjectInput,InputStream和Reader。
看看他们的继承关系:
ObjectOutput和ObjectInput类比较少,这里就不列出来了。
统计一下大概20个类左右,搞清楚这20个类的用处,恭喜你java IO你就懂了!
对于NIO来说比较复杂一点,首先,为了处理block的信息,需要将数据读取到buffer中,所以在NIO中Buffer是一个非常中要的概念,我们看下NIO中的Buffer:
从上图我们可以看到NIO中为我们准备了各种各样的buffer类型使用。
另外一个非常重要的概念是channel,channel是NIO获取数据的通道:
NIO需要掌握的类的个数比IO要稍稍多一点,毕竟NIO要复杂一点。
来源:https://www.cnblogs.com/flydean/p/io-nio-overview.html
猜你喜欢
- 目录1.堆空间的基本结构:2.空间分配担保机制3.如何判断一个对象已经无效4 不可达的对象并非“非死不可”5 如何判断一个常量是废弃常量?6
- 此次简单的操作将数据从数据库导出生成excel报表以及将excel数据导入数据库首先建立数据库的连接池:package jdbc;impor
- 前言现在是移动端产品疯狂的年代,随之,移动端支付也是热门小技能,最近本公司在做一个移动端,要接入微信支付和支付宝支付, * 惯,功能做完之后做
- 背景:本人不是Java开发人员,经过四年多的历练,可以说是一枚BI攻城师了吧,最近粗糙的写了一个Portal来集成cognos报表,下面就入
- 废话不多说,直接上代码,小伙伴们仔细看 * 释吧。/*简单的复制 剪切 粘贴 功能 操作: &nb
- 数组array和集合的区别:(1) 数值是大小固定的,同一数组只能存放一样的数据。(2) java集合可以存放不固定的一组数据(3) 若程序
- IDEA版本:2020.3具体步骤一、开启IDEA的自动编译【静态】1.File->Settings。2.直接搜索Compiler,选
- 本文实例为大家分享了C#二维码图片识别的具体代码,供大家参考,具体内容如下怎么用NuGet和怎么配置log4net就不介绍了,直接上代码(V
- 本教程为大家分享了学籍管理系统的具体java代码,供大家参考,具体内容如下1.需求分析 1.1系统功能设计 (1)能够查询学生的基本信息,如
- 简介redis 多数据源主要的运用场景是在需要使用多个redis服务器或者使用多个redis库,本文采用的是fastdep依赖集成框架,快速
- 以下实例演示了如何通过 Collections 类的 Collections.max() 和 Collections.min() 方法来查找
- import java.io.IOException;import javax.xml.parsers.*;import javax.xml
- JAVA源码编译由三个过程组成:1、源码编译机制。2、类加载机制3、类执行机制我们这里主要介绍编译和类加载这两种机制。一、源码编译代码编译由
- Java自定义注解一般使用场景为:自定义注解+ * 或者AOP,使用自定义注解来自己设计框架,使得代码看起来非常优雅。本文将先从自定义注解的
- 一、项目简述功能:用户的邮箱注册、验证码验证以及用户登录。 不需要注册账号,也可以上传满足条件的临时文件,但是只4小时内有效。 文件的管理,
- 实例如下所示:package test;import java.util.ArrayList;import java.util.Collec
- 本文详细分析了C#类的访问修饰符用法,分享给大家供大家参考。具体用法分析如下:默认情况下,类声明为内部的,即只有当前工程中的代码才能访问它。
- 一.线程池简介线程池的概念线程池就是首先创建一些线程,它们的集合称为线程池,使用线程池可以很好的提高性能,线程池在系统启动时既创建大量空闲的
- 一、定时器是什么定时器类似于我们生活中的闹钟,可以设定一个时间来提醒我们。而定时器是指定一个时间去执行一个任务,让程序去代替人工准时操作。标
- 1.实现方式说明本文在---- 手写redis @ Cacheable注解支持过期时间设置 的基础之上进行扩展。1.1问题说明