BufferedInputStream源代码学习笔记

一、变量含义

private static int DEFAULT_BUFFER_SIZE = 8192;//默认缓存大小8kb
private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE – 8;//某些数组的头部会保留8位
protected volatile byte buf[];//缓冲区
private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
AtomicReferenceFieldUpdater.newUpdater
(BufferedInputStream.class, byte[].class, “buf”);//缓存数组的原子更新器,该成员变量与buf数组的volatile关键字共同组成了buf数组的原子更新功能实现。
protected int count;//该成员变量表示目前缓冲区域中有多少有效的字节
protected int pos;//该成员变量表示了当前缓冲区的读取位置。 
protected int markpos = -1;//用于重置读取位置的标志
protected int marklimit;//保留重置标志markpos的值的区间极限。从pos开始不断的往前读数据bufReaded,当bufReaded的长度大于marklimit时,markpos会被重置为-1.

二、方法解读

fill()

获取buf。

无重置标志
有重置标志
   无可读字节
     标志位不是开头
        移动从标志位到length的字节数到数据开头,并设置重置标志为0,pos=length-mark;
     标志位是开头
         数组容量大于标志区间,则重置标志位
         数组容量小于标志区间,数组扩容

有可读字节
从输入源读取数据,pos,length-pos

这个方法其实判断的条件比较绕,所以看起来很费力。主要是受标志位markpos和marklimit影响。

按理,我们一般是这样区分的。buf有可读字节,则从pos继续填充length-pos个字节。buf无字节,则直接从头开始填充length个字节。

但是因为有标志位markpos,所以当标志位在buf中间,我们想保留标志位开始的数据。但是又因为无数据可读,所以要清空buf。两者就冲突了,所以,不能清空buf,只能清空部分buf,把标志位到末尾的数据已到buf开头去,然后再填充buf。

另外标志位等于-1和等于0没什么区别,所以是否重置标志位为-1不要近。关键是pos要根据是否扩容来确定具体位置。

read()

   主要判断buf是否有可读的字节,无则填充,填充后还是无则返回-1,read失败。

read1(byte[], int, int)非贪婪读取

  无可读数据,并且读取长度超过buf大小,并且无标志位,直接从原始输入流中读取。这是巧妙之处,节省了将数据读到缓冲区的性能损耗。

  当读取的长度超过buf长度时,仅读取buf剩余的全部未读数据。须留意。

read(byte[], int, int)贪婪读取,

  多次调用read1(byte[], int, int),知道读取了 指定长度的字节数。

mark(int)

  主要是设置最长的标志区间。该标志位会影响buf的扩容。

Author: bkdwei