背景

最近在看socket编程,这里面需要用到stream进行数据的读取和写入。于是代码中用到了BufferedInputStream提高读的效率。所以就一直在想为什么加上buffer就能提高效率了,加上之前面试的时候曾有面试官问到过这个问题,当时没有回答上来,并且就上网搜索了一下,发现有个文章是为什么缓存能提高io效率,这个文章中说是因为缓存可以让DMA来处理io流,后面我一直都是这么认为的,今天在网上搜索发现即使你用的是inputstream来读也会用到DMA,那篇文章中的缓存可能指的是内核态的缓存。所以之前以为的应该都是错误的吧。

猜想

在进行io流的读时,最消耗时间的应该是数据从内核态拷贝到用户态这个过程,这个过程会进行上下文的切换,详细的内容可以搜索一下。
     接下来看一下BufferedInputStream的代码。
1、首先是初始化,如果不指定缓冲区的大小,会默认8192长度的数组

2、查看BufferedInputStream的read()方法。
read()方法中有个fill()方法,这里的read()方法其实是加锁的,猜想应该是防止多线程调用的时候造成缓存数组的数据混乱,查看full方法的调用的是原生inputstream的public int read(byte b[], int off, int len) throws IOException 方法,注意这里第一个参数是传入了一个byte数组。


分析
既然BufferedInputStream的read()方法最终还是会调用FileInputStream的read方法,那是不是所如果直接使用FileInputStream的public int read(byte b[]) 方法也能提高效率。

用三种方法读取7.8M的文件,测试结果如下:
结果基本可以看出使用原生FileInputStream的read(byte[] b)方法效率也是可以高很多的

测试代码

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;/*** @author * @Description* @create 2022-02-17 14:56*/
public class TestInputStream {private final static String FILENAME = "input-test.txt";public static void main(String[] args) {testOutputStream();testInputStream(false);testInputStream(true);testBufferInputStream();}/**** @param isbuffer  是否使用原生的inputstream中的byte[]*/public static void testInputStream(boolean isbuffer) {FileInputStream in = null;int byteLen = 8192;// 每次读取1024字节byte[] buffer = new byte[byteLen];try {in = new FileInputStream(FILENAME);long start = System.currentTimeMillis();while (true) {int read;if (isbuffer) {read = in.read(buffer);if (read == -1 || read < byteLen) {break;}}else {read = in.read();if (read == -1) {break;}}}long end = System.currentTimeMillis();System.out.println("total = " + (end - start));} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (in != null) {in.close();}} catch (IOException e) {e.printStackTrace();}}}public static void testBufferInputStream() {FileInputStream inputStream = null;BufferedInputStream in = null;try {inputStream = new FileInputStream(FILENAME);in = new BufferedInputStream(inputStream);long start = System.currentTimeMillis();while (true) {int read = in.read();if (read == -1) {break;}}long end = System.currentTimeMillis();System.out.println("total = " + (end - start));} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if (in != null) {in.close();}} catch (IOException e) {e.printStackTrace();}}}public static void testOutputStream() {String context = "年薪百万,年薪百万,年薪百万,年薪百万,年薪百万,年薪百万,年薪百万,年薪百万,年薪百万,年薪百万,年薪百万\r\n";FileWriter fileWriter = null;try {fileWriter = new FileWriter(FILENAME);// 文件大概7.8Mfor (int i = 0; i < 50000; i++) {fileWriter.append(context);}} catch (IOException e) {e.printStackTrace();}finally {try {if (fileWriter != null) {fileWriter.close();}} catch (Exception e) {e.printStackTrace();}}}
}

以下是FileInputStream中的read(byte b[])和read()的代码,native方法调用的就是系统方法了。耗时应该都是在这里。

总结猜想

BufferInputStream提高效率应该是针对read()方法,也就是不带任何参数的read方法,BufferInputStream会调用FileInputStream的read(byte b[], int off, int len),这个方法可以直接指定从系统中一次读取多大的文件,当用户调用read()方法时其实是从read(byte b[], int off, int len) 返回的结果中取一个字节数据,这样也就减少了和系统的交互次数,进而减少上下文切换的时间消耗,体现给我们的就是读取文件的时间大幅减小。
举个例子:
    假如一个文件大小为100,如果调用FileInputStream没有参数的read() 方法,则需要和系统交互100次,但是如果调用read(byte b[], int off, int len),并且指定一次读取的大小为20,那么只需要和系统交互5次就能将文件全部读完,这样就大大的降低的读取时间。

java中BufferedInputStream缓存为什么使IO效率高?相关推荐

  1. Java中的File类和IO流

    Java中的File类和IO流 File类 java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建.查找和删除等操作. File的分隔符 import java.io.Fi ...

  2. java中Cache缓存的使用

    java中Cache缓存 1.JSR107 缓存的整体架构: 2.SpringBoot的缓存抽象 几个重要概念以及缓存注解 其中想要使用缓存直接,就必须开启**@EnableCaching**注解 开 ...

  3. 【java】java中内存映射文件和IO

    转载:https://leokongwq.github.io/2017/02/25/java-memorymapped-file-and-io.html 对大多数Java开发人员来说,Java中的内存 ...

  4. NIO 拷贝文件真的比 IO 效率高 ?

    本文是基于单线程的NIO和IO拷贝文件比较, 并未对并发做测试, 请勿过度纠结场景! 今天发现项目中有个FileUtils.copy的工具方法, 打开后发现是基于io的, 我给改成了基于NIO的, 突 ...

  5. Java 中常用缓存Cache机制的实现

    /* *所谓缓存,就是将程序或系统经常要调用的对象存在内存中,以便其使用时可以快速调用,不必再去创建新的重复的实例.这样做可以减少系统开销,提高系统效率. *内存缓存,也就是实现一个类中静态Map,对 ...

  6. JAVA中DNS缓存设置

    我们上网的原点就是打开浏览器,在上方地址栏输入网址的那一刻,这个回车按了之后,发生了很多事情.首先,计算机只懂0和1,也就是说人类的字母网址计算机是不懂的,它只认识IP地址,如果是IPV4那就是4组8 ...

  7. 聊一聊JAVA中的缓存规范 —— 虽迟但到的JCache API与天生不俗的Spring Cache

    为何需要规范 上一章中构建的最简化版本的缓存框架,虽然可以使用,但是也存在一个问题,就是它对外提供的实现接口都是框架根据自己的需要而自定义的.这样一来,项目集成了此缓存框架,后续如果想要更换缓存框架的 ...

  8. java中一级缓存_JavaWeb_(Hibernate框架)Hibernate中一级缓存

    Hibernate中一级缓存 Hibernate 中的缓存分为一级缓存和二级缓存,这两个级别的缓存都位于持久化层,并且存储的都是数据库数据的备份.其中一级缓存是 Hibernate 的内置缓存,在前面 ...

  9. java中一级缓存二级缓存_[Java] hibernate 一级缓存和二级缓存

    缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事 ...

最新文章

  1. SPP pooling layer
  2. servlet请求与响应的练习实例
  3. (10)verilog语言编写SPI发送
  4. 生成图片_GitHub Star 3.2K Java 图片缩略图生成库
  5. 生活在REPL中(续):在REPL中动态加载依赖的库
  6. 做一个消息自动回复,但是回复内容可以在网页上面输入,用input接收,错了,别人有新增选项,本身就是在页面进行新增,页面维护...
  7. Vue webpack打包后,css样式发生改变或不起作用
  8. JAVA笔记自整理(Java)
  9. SI4463模块使用心得(无线协议)
  10. 谷歌浏览器JSON格式化插件
  11. 盖世兔I9100刷机心得
  12. MVP是什么,不是什么
  13. 7.java IO流
  14. 机器学习常见面试题总结
  15. 任意大小 内存池 c语言,C语言内存池使用模型-1 - Mr.南柯 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
  16. 鸿蒙系统第一批升级名单,鸿蒙系统首批升级名单详细介绍
  17. 【Python百日基础系列】Day02-Python语法基础
  18. sql UPDATE的时候可以使用join吗
  19. R绘制股票走势图及年份成交量图
  20. 奥里给,干了兄弟们。

热门文章

  1. Qt扫盲-QScrollArea理论总结
  2. 【漫画】程序员被KPI追赶的一生
  3. 【干货】大数据创新驱动智慧民生
  4. 【语音识别入门】概述
  5. 基于python的pyshp库读取.shp数据来获取中国城市边界的经纬度数据,并生成hdf文件
  6. find 命令常用用法
  7. linux搭建ldap服务器详细步骤,linux环境搭建ldap服务器
  8. java计算机毕业设计中小型饭馆餐饮管理系统源码+mysql数据库+系统+lw文档+部署
  9. Java项目:基于java+ssm知了堂财务报账管理系统(计算机毕业设计)
  10. 使用Snagit安安静静的截屏并保存