Buffer#Capacity,Position 和 Limit

Buffer本质上一个能读写的 内存块 ,在Java中被包装成一个 NIO Buffer 对象。Buffer的3个属性

  • capacity
  • position
  • limit

分别对应buffer的容量,读写的位置,能够读写的最大值.

写模式下, position代表当前写入的位置,limit代表写入的最大量,一般等于capacity

读模式下,position代表当前读取的位置,limit代表能够读取的最大量,相当于写模式下position的位置。

借用一幅图表示

NIO Buffer - 图1

Buffer capacity, position and limit in write and read mode.

PS:容量的大小是确定的,在容量满时需要清空才能再次写入 , Netty 提供了可扩容的 Buffer.

filp,slice,和duplicate

  • filp: 英文翻译为反转
  • slice: 切片
  • duplicate: 复制

filp 用于切换 读写模式 . 创建Buffer时是写入模式,读取时需要切换才能进行读取. 切换时主要变更 Buffer的position和limit.

  1. public class Test {
  2. public static void main(String[] args) {
  3. ByteBuffer allocate = ByteBuffer.allocate(16);
  4. allocate.putInt(1);
  5. allocate.flip();
  6. System.out.println(allocate.getInt());
  7. }
  8. }

slice 创建一个Buffer , 共享 父Buffer 的内容, 在 slice 中的修改会直接反馈在 父Buffer中, Position,Limit,capacity 相互独立.

主要在不切换父Buffer时使用 , 在 RocketMq 中出现该使用方式

  1. public class SliceTest {
  2. public static void main(String[] args) {
  3. ByteBuffer allocate = ByteBuffer.allocate(16);
  4. //切片1
  5. ByteBuffer slice = allocate.slice();
  6. slice.position(0);
  7. slice.putInt(1);
  8. //切片2
  9. ByteBuffer two = allocate.slice();
  10. two.position(4);
  11. two.putInt(2);
  12. System.out.println(allocate.getInt());//输出1
  13. System.out.println(allocate.getInt());//输出2
  14. }
  15. }

创建的ByteBuffer没有直接使用,而是通过共享的slice去进行修改,slice的修改会直接反馈在allocate的内容当中,省去了 filp . 避免了忘记 filp 的错误.

duplicate 复制一个Buffer ,所有的数据和父Buffer保持一致,3个属性值项目独立.

  1. public class DuplicateTest {
  2. public static void main(String[] args) {
  3. ByteBuffer allocate = ByteBuffer.allocate(16);
  4. allocate.putInt(1);
  5. ByteBuffer duplicate = allocate.duplicate();//复制buffer
  6. allocate.putInt(2);
  7. duplicate.flip();
  8. System.out.println(duplicate.getInt());//输出1
  9. System.out.println(duplicate.getInt());//输出2
  10. }
  11. }

读写示例

通过 slice 写入,不需要通过 filp ,后读取数据. 限于篇幅贴了部分代码 ,代码地址 MessageWrite.java

  1. public class MessageWrite {
  2. public static void main(String[] args) throws Exception {
  3. ByteBuffer map = ByteBuffer.allocate(1024);
  4. AtomicInteger at = new AtomicInteger(0);
  5. ByteBuffer byteBuffer = map.slice();
  6. byteBuffer.position(at.get());
  7. Message message = new Message();
  8. message.setBody("我为人人,人人为我".getBytes());
  9. message.setTopic("chenshun00");
  10. message.setProperties(new HashMap<String, String>() {{
  11. this.put("11", "11");
  12. this.put("22", "22");
  13. this.put("33", "33");
  14. }});
  15. at.set(writeMessage(message, byteBuffer));
  16. Message read = read(map);
  17. System.out.println(read.id);
  18. System.out.println(read.getProperties().toString());
  19. System.out.println(read.getTopic());
  20. System.out.println(new String(read.getBody()));
  21. }
  22. public static int writeMessage(Message message, ByteBuffer byteBuffer) {
  23. return 0;
  24. }
  25. public static Message read(ByteBuffer byteBuffer) {
  26. return null;
  27. }
  28. private static String toStr(Map<String, String> xx) {
  29. return JSONObject.toJSONString(xx);
  30. }
  31. private static Map<String, String> toMap(String json) {
  32. return JSON.parseObject(json, new TypeReference<HashMap<String, String>>() {
  33. });
  34. }
  35. }

参考

Java NIO Tutorial