Buffer, ByteBuffer and ... - tenji/ks GitHub Wiki

Buffer, ByteBuffer and ...

目前很多高性能的 Java RPC 框架都是基于 Netty 实现的,而 Netty 的设计原理又离不开 Java NIO。Buffer 是 NIO 核心三件套之一(BufferSelectorChannel)。

一、Buffer 的继承体系

二、主要标志位说明

标志位 初始值 说明
mark -1 标记位
position 0 当前位置
limit 指定的缓冲区容量 已写入有效数据容量
capacity 指定的缓冲区容量 缓冲区容量

三、Buffer 使用案例

四、Buffer 的基本原理

Buffer 缓冲区本质上就是一个特殊类型的数组对象,与普通数组不同的地方在于,其内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如果我们使用 get() 方法从缓冲区获取数据或者使用 put() 方法把数据写入缓冲区,都会引起缓冲区状态的变化。

五、Buffer 主要操作

5.1 Put

顾名思义,put 操作就是就是将数据放入缓冲区中,每一次 put 操作,都会 position 加上 put 进去的数据长度。position 每加一,代表缓冲区内增加了一个字节的数据。

如果送入的数据大小大于缓冲区剩余容量,则会抛出异常 java.nio.BufferOverflowException,虽然可能有实际部分数据被写入缓冲区,但是 flip 之后,limit 位置还是最后一次正确写入缓冲区的位置。

5.2 Flip

Flip,从英文的直译为:翻转。但是,这并不是将数据翻转的意思,而其实是让 limit 指向当前 position 的位置,position 指向起始位置,此时 position = 0,进行这一部操作之后,就可以确定了当前缓冲区的有效数据。并且为数据读取做准备。

源码:

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

5.3 Get

Get 操作,就是按照 position 当前位置,取出缓冲区的数据,每一次取操作之后,position 都会 get 出的数据长度。同样,position 每加一,代表从缓冲区内读取到了一个字节的数据,不过数据并不会被删除,只是单纯的读取操作。

如果,get 之后,position 值大于 limit 值,则抛出异常:java.nio.BufferUnderflowException

5.4 Mark & Reset

5.5 Clear

Clear 操作很简单,就是清空缓冲区的所有数据。因此,所有标志位都会被恢复成默认值,包括 mark 值,但是记住,不是数据,写入缓冲区的数据仍然保留,如果这时候执行 get 操作,仍然可以将数据获取出来。

源码:

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

4.6 Slice

slice 方法的作用,就是做数据分割,将当前的 position 到 limit 之间的数据分割出来,返回一个新的 ByteBuffer,同时,mark 标记重置为 -1。不过这里注意,分割出来的数据的容量刚好就是数据长度,而不是被分割之前的长度。

参考链接