前言

  Java I/O功能封装的很好,使用起来很方便,就是刚开始学的时候,如果不了解装饰器模式,会被他繁多的类给吓到。用多了也就习惯了,而且现在有很多实用的封装良好的实用类,可直接读写整个文件。开发者不知道底层实现细节,也可以灵活使用,这是封装的一大优点。但是,作为一名软件开发人员,对其所使用的代码不能仅仅停留在熟悉功能特性上,最好对其实现原理也要有一定了解。

注:本文引用了部分外文内容,并根据自己的理解进行了翻译,连接将在文末贴出。

缓冲处理、内核空间vs用户空间

--------------------------------------外文引用内容Begin(已翻译)----------------------------------------------------------------

  缓冲,以及如何处理缓冲是所有IO的基本内容。术语"I/O"(输入输出)指的不过就是从缓冲区移入或移除数据。通常,进程执行I/O操作的方式是,向操作系统发送请求,请求其填充自己的缓冲区(或者把自己缓冲区的内容写出)。这就是I/O这个概念的全部内容。要实现这些传输操作,操作系统底层的实现非常复杂。但是在概念上,本文所要讲述的内容则非常直白。

  

  注意:User space和Kernel space 都属于内存。内存分为两个区,用户区和系统区(内核区)。

  上图简要展示了,块数据如何从外部源头(比如硬盘)移入到进程的内存空间的过程。首先,这个进程通过系统调用read(),请求填充自己的缓冲区。这将导致内核发送一个命令到磁盘控制器,使其从磁盘中抓取数据。磁盘控制器通过DMA把数据直接写入到内核空间缓冲区,这个过程不需要CPU干预。一旦磁盘控制器完成了填充数据的任务,内核就将数据从内核空间的临时缓冲区转移到进程指定的缓冲区内。

  有一件事需要注意,内核会试图缓冲或者说预加载一些数据,所以有可能进程所请求的数据已经在内核空间里了。如果这样的话,进程请求的数据,只需要从内核缓冲区拷贝一份即可。如果数据不在内核空间内,则在内核获取数据到内存的过程中,此进程将被挂起。

--------------------------------------外文引用内容End(已翻译)-------------------------------------------------------------------

从上述内容可知:

  • Java的读写操作,底层由C/C++实现。而不是直接与OS接触
  • C/C++读写操作,需要OS服务
  • 内核自带缓冲,会过分加载
  • 如果内存中没有数据的缓冲,读写操作将阻塞当前线程(OS会帮你挂起线程)

DMA

  DMA(Direct Memory Access,直接内存存取)是I/O设备控制方式的一种。我个人认为它们的主要差别在于CPU的参与I/O控制的程度

I/O设备控制方式有:

  • 程序I/O方式——CPU需反复检查
  • 中断I/O方式——每完成一个字节的读写,通知CPU
  • DMA方式——每完成一个块(多字节)的读写,通知CPU
  • I/O通道方式(暂不了解)

在DMA读写I/O设备的时候,CPU不会被影响,它可以继续执行。注意!这里能继续执行,指的是CPU可以继续运行,而此I/O操作的线程已经被挂起,不参与CPU调度。I/O操作完成后,该线程才被唤醒,参与调度(加入就绪队列,等待时间片)

系统调用

  系统调用是应用程序间接调用OS函数的方式。C语言有提供与系统调用相对应的库函数。这里就是read、write。 

BufferedXXStream

  注意,对于Java来说,系统调用的开销是比较大的。首先读写操作要触发的是本地方法read0,readBytes,write0,writeBytes,这里JNI需要一定开销。还有就是每产生一个系统调用,就可能产生上千个机器指令,这种开销是不容小觑的。所以,我们要尝试减少系统调用。那有人就会问了,不行啊,我数据又不能缺斤少两,少读少写肯定出问题,怎么减少调用?这不是很好解决吗,每次多读写一点,调用的次数不就少了嘛。而BufferedXXStream就是这么用的,例如,BufferedInputStream的read无参方法只读取一个字节,而实际上BufferedInputStream默认读取了8kb,这些数据用字节数组保留。

     对了,如果对上图,不是很理解,可以看看这张。

   即运行时,有一个对象BufferedInputStream,其调用一次read()方法,数据保留到buf数组中。

参考文献  

How Java I/O Works Internally at Lower Level?(外网)

【杂谈】Java I/O的底层实现的更多相关文章

  1. 如何精确地测量java对象的大小-底层instrument API

    转载: 如何精确地测量java对象的大小-底层instrument API 关于java对象的大小测量,网上有很多例子,大多数是申请一个对象后开始做GC,后对比前后的大小,不过这样,虽然说这样测量对象 ...

  2. Java进阶(二十五)Java连接mysql数据库(底层实现)

    Java进阶(二十五)Java连接mysql数据库(底层实现) 前言 很长时间没有系统的使用java做项目了.现在需要使用java完成一个实验,其中涉及到java连接数据库.让自己来写,记忆中已无从搜 ...

  3. 《Java并发编程的艺术》Java并发机制的底层实现原理(二)

    Java并发机制的底层实现原理 1.volatile volatile相当于轻量级的synchronized,在并发编程中保证数据的可见性,使用 valotile 修饰的变量,其内存模型会增加一个 L ...

  4. 【java并发编程艺术学习】(三)第二章 java并发机制的底层实现原理 学习记录(一) volatile

    章节介绍 这一章节主要学习java并发机制的底层实现原理.主要学习volatile.synchronized和原子操作的实现原理.Java中的大部分容器和框架都依赖于此. Java代码 ==经过编译= ...

  5. Java 并发系列之二:java 并发机制的底层实现原理

    1. 处理器实现原子操作 2. volatile /** 补充: 主要作用:内存可见性,是变量在多个线程中可见,修饰变量,解决一写多读的问题. 轻量级的synchronized,不会造成阻塞.性能比s ...

  6. Java并发机制的底层实现原理之volatile应用,初学者误看!

    volatile的介绍: Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现 ...

  7. java常用集合框架底层实现简介与注意点

    Collection: ArrayList:1:底层实现是数组,默认长度是10.2:add(),判断是否数组越界,是数组扩容为原来的两倍.3:remove(),copy数组,size-1,释放空虚的空 ...

  8. 再学Java 之 HashMap的底层实现

    今天参加欢聚时代的面试,我说我自己依靠自己的理解重新实现过HashMap.描述我自己的实现思想后,面试官问“hashmap”底层如果用数组不是效率比较低吗,不是更应该用红黑树吗?我一下子就蒙了.用数组 ...

  9. JAVA框架 Spring AOP底层原理

    一:AOP(Aspect Oriented Programming)面向切面编程. 底层实现原理是java的动态代理:1.jdk的动态代理.2.spring的cglib代理. jdk的动态代理需要被代 ...

随机推荐

  1. Leetcod--20. Valid Parentheses(极简洁的括号匹配)

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  2. noip第8课资料

  3. Hdu1016 Prime Ring Problem(DFS) 2016-05-06 14:27 329人阅读 评论(0) 收藏

    Prime Ring Problem Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  4. HDU3480_区间DP平行四边形优化

    HDU3480_区间DP平行四边形优化 做到现在能一眼看出来是区间DP的问题了 也能够知道dp[i][j]表示前  i  个节点被分为  j  个区间所取得的最优值的情况 cost[i][j]表示从i ...

  5. 在linux上搭建nexus私服(CentOS7)

    1.下载nexus安装包,下载地址 https://www.sonatype.com/download-oss-sonatype?hsCtaTracking=920dd7b5-7ef3-47fe-96 ...

  6. 记Asp.Net Core Swagger 使用 并带域接口处理

    引用作者原话:Asp.Net的WebApi中使用Swagger作为说明和测试的页面是非常不错的,比起WebApiTestClient来至少在界面上的很大的提升.但是使用Swagger时如果只是一般的控 ...

  7. WPF实战案例-数据代理

    在我们wpf开发中,很多人会有mvvm模式去做wpf的项目. 是否有人遇到这样一个场景:在一个界面上,有个tabcontrol上面有4个页签,每个页签里面都有一个datagrid,里面显示的列基本一样 ...

  8. MVC+Nhibernate+spring.net(二)

    在上一篇文章中我们已经把数据查了出来,现在我们来完善一下:前台使用easyui 首先我们将NHelper类完善一下 public class EmpDal { public IList<Emp& ...

  9. OSLab多进程

    日期:2019/3/23 内容:Linux下与多进程相关的函数.     进程基本知识 定义 应用程序关于某数据集合上的一次运行活动. 特点 ·操作系统进行资源分配和调度的基本单位 ·进程是程序的一次 ...

  10. Android-----application的学习

    一.Application的对象回调函数 1.onCreate : Application对象被创建时候会调用 2.onConfigurationChanged : 屏幕方向变化.系统语言的更改等 3 ...