JavaNio中的ByteBuffer

437 阅读2分钟

这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战

ByteBuffer中的核心属性

  1. position 缓冲区读取的位置
  2. limit 目前缓冲区的可读位置
  3. capacity 缓冲区的容量
  4. mark 在缓冲区的某一位置打标记

申请一块1024大小的ByteBuffer

可以通过ByteBuffer提供的静态方法直接申请基于byte数组的缓冲区ByteBuffer.allocate(capacity)和基于堆外内存的缓冲区ByteBuffer.allocateDirect(capacity)

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        System.out.println(byteBuffer);

输出:

java.nio.HeapByteBuffer[pos=0 lim=1024 cap=1024]

因为是新申请的byteBuffer,所以,limit=capacity,position=0

向ByteBuffer写入数据

写入helloworld字符到ByteBuffer

        byteBuffer.put("helloworld".getBytes(StandardCharsets.UTF_8));
        System.out.println(byteBuffer);

输出:

java.nio.HeapByteBuffer[pos=10 lim=1024 cap=1024]

因为helloworld的长度为10,所以,position的位移变为10,limit和capacity都没有变化

向ByteBuffer读数据

JDK提供的缓冲区,读写数据用的都是position指针,所以,在读数据之前,需要将position指针通过调用flip方法移动到缓冲区起始位置。

        byteBuffer.flip();
        System.out.println(byteBuffer);
        byte[] data = new byte[5];
        byteBuffer.get(data);
        System.out.println(new String(data,StandardCharsets.UTF_8));
        System.out.println(byteBuffer);

输出:

java.nio.HeapByteBuffer[pos=0 lim=10 cap=1024]
hello
java.nio.HeapByteBuffer[pos=5 lim=10 cap=1024]
  1. 调用flip方法后,可以看到不仅将position重置,而且将limit的值设置为原writePosition时的位置。
  2. 读取5个byte后,position跟我们预期的保持一致,在坐标为5的位置。

mark的作用

mark相当于在缓冲区的某个位置做一个标记,然后进行读取操作,当需要将指针放到刚才mark的位置时,调用reset方法即可。

        byteBuffer.mark();
        System.out.println(byteBuffer);
        byte[] data1 = new byte[5];
        byteBuffer.get(data1);
        System.out.println(new String(data1,StandardCharsets.UTF_8));
        System.out.println(byteBuffer);
        byteBuffer.reset();
        System.out.println(byteBuffer);

可以看出,position指针由原来的5读取完5个byte后变为10,通过reset后又变为了5

Rewind和Flip的区别

Rewind和Flip的源码如下:

    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
        }
    public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }
  1. 这两个API都可以将position的值和mark的值重置,
  2. Rewind不会设置limit的大小,但是flip会将原position的值赋值给limit

ByteBuffer的缺点

  1. 申请的内存空间大小是固定的不能动态的扩缩容
  2. 读取和写入的操作都是基于position,在实际应用场景中,会产生大量的调用flip方法,开发人员要不断的根据程序的读写不停的操作position指针,编码体验较差,
  3. 没有引入内存池的概念,频繁的创建和销毁ByteBuffer对系统开销较大。

关于ByteBuffer的介绍就说这么多,下一讲会介绍Netty中对ByteBuffer的优化。~~