前言

  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. 基于SVG+AJAX的网页数据监控

    这个是前一阵做的一个火灾报警主机数据网页监控,前后台主要耗时5小时.绘图2小时,配置后端采集端1小时,测试2小时. 用的SVG,上面画的指示灯可以实时显示传感器的状态. 用开源方案实现. 如果集成到自 ...

  2. POJ3020 Antenna Placement

    Antenna Placement Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9586   Accepted: 4736 ...

  3. IP地址和域

    1. 0. 0. 0到 126.255.255.255为A类 主要分配给具有大量主机而局域网络数量较少的大型网络 128.0.0.0到191.255.255.255为B类 一般用于国际性大公司和政府机 ...

  4. 谷歌的java文本差异对比工具

    package com.huawei.common.transfertool.utils; /** * @author Paul * @version 0.1 * @date 2018/12/11 * ...

  5. JAVA本地读取文件,解决中文乱码问题

    JAVA本地读取文件出现中文乱码,查阅一个大神的博客做一下记录 import java.io.BufferedInputStream;import java.io.BufferedReader;imp ...

  6. sed,grep,进阶+source+export+环境变量

    三剑客之sed 概括流程:从文件或管道中,可迭代读取. 命令格式: sed(软件) 选项 sed命令 输入文件 增 两个sed命令: a: 追加文本到指定行后 i: 插入到指定行前 sed -i '1 ...

  7. https://www.cnblogs.com/hnxxcxg/p/6085149.html

    DELPHI微信支付代码   不管是微信支付还是支付宝支付, 3个最棘手的问题是:1,如何生成签名2,支付请求如何提交3, 如何验证签名 下面就围绕这二个问题来讲. 我使用的是XE3. 先看微信支付: ...

  8. ubuntu16.04 LTS把下载源改为阿里云的源

    为什么要切换下载源到国内的源上? Ubuntu的中国服务器下载速度很慢,我们可以尝试修改软件更新源,这样下载和更新软件的速度会加快很多. 一.linux系统版本: ubuntukylin-16.04- ...

  9. 二、基于kubernetes构建Docker集群环境实战

    kubernetes是google公司基于docker所做的一个分布式集群,有以下主件组成 etcd: 高可用存储共享配置和服务发现,作为与minion机器上的flannel配套使用,作用是使每台 m ...

  10. 企业项目开发--cookie(2)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2.1.3.CookieUtil:(cookie的基本操作:增删查,注意没有改)  1 package co ...