NIO浅谈之Buffer基本原理

NIO从整体上分类来看可以看做由这几个部分组成:Buffer,Channel,Selector组成。本篇文章从浅谈一下Buffer。

1:Buffer的类型。可以这么来说,不同的数据类型有不同的buffer,例如ByteBuffer,IntBuffer,LongBuffer,ShortBuffer。。分别对应的数据类型为byte,int,long,short。

2:想获取一个Buffer对象的话首先要进行buffer对象的分配,每一个Buffer类都有一个allocate的方法。具体用法:

ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);

观察如上的代码,创建一个具体的Buffer对象都要使用相关的Buffer类的allocate方法。到这里,可能就会有同学有疑问了,为什么不能直接new出来。下面,进入ByteBuffer源码里看一眼。

public abstract class ByteBuffer
    extends Buffer
    implements Comparable
public static ByteBuffer allocate(int capacity) {
        if (capacity < 0)
            throw new IllegalArgumentException();
        return new HeapByteBuffer(capacity, capacity);
    }

估计可以看出一些门道来了,ByteBuffer是一个抽象类,allocate是抽象类中的静态方法,通过allocate方法构造的是HeapByteBuffer对象。

由此,推断出其他数据类型的Buffer也是一个抽象对象,通过allocate方法构造出具体的对象来。因此,又去IntBuffer源码中看了一眼,果不其然,如下图:

public abstract class IntBuffer
    extends Buffer
    implements Comparable


    public static IntBuffer allocate(int capacity) {
        if (capacity < 0)
            throw new IllegalArgumentException();
        return new HeapIntBuffer(capacity, capacity);
    }

 

接下来,为了理解buffer的工作原理,看下buffer的三个属性

capacity【容量】

position【位置】

limit【界限】

关于这三个属性之间的关系,找了一个比较易懂的图片来解释下

左边的代表写入的时候,右边的代表读取的时候

当写入的时候,capacity的大小代表利用allocate初始化时候的大小,代表这个缓存块的容量,最多只能向这个缓存块中放入capacity个char,long,int,byte等等。当缓存块满了的时候需要将其清空,才能继续往里面写数据

position:代笔当前位置,初始化值为0,当一个数据写入buffer中的时候,position会移动到下一个可插入的buffer单元,因此,position的最大值为position-1,

limit:在写的模式下面,limit表示你最多可以向buffer里面写入多少个buffer数据,在写模式下面,limit=capacity。

当切换到读模式下面,代表最多能读取到多少数据。因此当切花到读模式下面,limit会被置为写模式下面的position值。因此,你能读取到在写模式下面写入的所有值。

 

以上的话,就是这三个属性的具体介绍。

理解了这三个属性之后,对于理解buffer的一些方法有很大的用处。

1:rewind方法:主要是讲position置为0,因此,我们可以从头开始重新读取一遍数据,limit保持不变。

2:clear与compact方法。当读取完数据之后可以通过这两个方法来继续让buffer准备好继续写入

public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

因此,通过clear的方法之后,会将position置为0,limit置为容器大小,相当远将容器清空,所以这时候即使有未处理的数据也不会再被读取出来。

但是compact方法,会将position置为 limit-position,意味着什么,假设limit=10,position=3,意味着这个缓存块我们已经读到第三个,还剩下7个没有读,最新的position=7,也就是最新一次存数据会从第7个开始写,并且会将原来未读取的数据copy一份放在前7个块中。

public ByteBuffer compact() {

        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
        position(remaining());
        limit(capacity());
        discardMark();
        return this;



    }

flip 当我们从写模式切换到读模式的时候使用。

 public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

理解了这三个属性的意思之后,看下代码直接明白什么意思了,将limit=position。意思为在读模式下可以读取最多的数据是多少,position=0说明读取开始的位置。

你可能感兴趣的:(NIO)