Buffer, ByteBuffer and ... - tenji/ks GitHub Wiki
Buffer, ByteBuffer and ...
目前很多高性能的 Java RPC 框架都是基于 Netty 实现的,而 Netty 的设计原理又离不开 Java NIO。Buffer
是 NIO 核心三件套之一(Buffer
、Selector
、Channel
)。
一、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。不过这里注意,分割出来的数据的容量刚好就是数据长度,而不是被分割之前的长度。