远方的灯塔 - 专注于服务端技术分享 远方的灯塔 - 专注于服务端技术分享
首页
  • Java SE
  • Struts2
  • Hibernate
  • MyBatis
  • JAX-WS
  • 并发
  • 分布式
  • Git
  • 文章分类
  • 文章标签
  • 文章归档
  • 《C程序设计语言》
心情随笔
友情链接
给我留言 (opens new window)
关于我
GitHub (opens new window)

Terwer Green

一个后端老菜鸟
首页
  • Java SE
  • Struts2
  • Hibernate
  • MyBatis
  • JAX-WS
  • 并发
  • 分布式
  • Git
  • 文章分类
  • 文章标签
  • 文章归档
  • 《C程序设计语言》
心情随笔
友情链接
给我留言 (opens new window)
关于我
GitHub (opens new window)
  • JavaSE

  • 开源框架

  • Linux

  • Struts2

  • Hibernate

  • Webservice

  • 分布式

    • RPC架构设计及IO模型
    • NIO编程及其三大核心原理
    • NIO三大核心之缓冲区(Buffer)
      • NIO三大核心之通道(Channel)
      • NIO三大核心之选择器(Selector)
      • Netty核心原理
      • 线程模型以及传统IO阻塞模型
      • Reactor模型
      • Netty线程模型
      • Netty核心API介绍
      • Netty入门与异步模型
      • Netty高级进阶之Netty编解码器
      • Netty高级进阶之基于Netty的群聊天室案例
      • Netty高级进阶之基于Netty的HTTP服务器开发
      • Netty高级进阶之基于Netty的Websocket开发网页聊天室
      • Netty高级进阶之Netty中的粘包和拆包的解决方案
      • Nety源码剖析
      • 自定义RPC框架之分布式架构网络通信理论
      • 自定义RPC框架之基于Netty实现RPC框架
      • 分布式架构理论
      • 分布式理论之数据一致性
      • 分布式理论之CAP定理
      • 分布式理论之BASE定理
      • 分布式一致性协议之两阶段提交协议(2PC)
      • 分布式一致性协议之三阶段提交协议(3PC)
      • 分布式一致性协议之NWR协议
      • 分布式一致性协议之Gossip协议
      • 分布式一致性协议之Paxos协议
      • 分布式一致性协议之Raft协议
      • 分布式一致性协议之Lease机制
      • 分布式系统设计策略之心跳检测
      • 分布式系统设计策略之高可用
      • 分布式系统设计策略之容错性
      • 分布式系统设计策略之负载均衡
      • 分布式架构服务调用
      • 分布式服务治理之服务协调
      • 分布式服务治理之服务削峰
      • 分布式服务治理之服务降级
      • 分布式服务治理之服务限流
      • 分布式服务治理之服务熔断
      • 分布式服务治理之服务链路追踪
      • 架构设计基本原则之开闭原则(OCP)
      • 架构设计基本原则之单一职责原则(SRP)
      • 架构设计基本原则之接口隔离原则(ISP)
      • 架构设计基本原则之里式替换原则(LSP)
      • 架构设计基本原则之依赖倒置原则(DIP)
      • 架构设计基本原则知识扩展
      • 分布式架构知识拓展与总结
    • 分布式框架

    • 后端开发
    • 分布式
    terwer
    2022-05-04
    目录

    NIO三大核心之缓冲区(Buffer)

    # 缓冲区(Buffer)

    # 基本介绍

    缓冲区(Buffer):缓冲区本质上是一个可读可写的内存块。

    可以理解成一个数组,该对象提供了一组方法,可以轻松的操作内存块。

    缓冲区内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。

    Channel提供从网络读取数据的通道,但是读取或者写入数据都必须经过Buffer。

    image-20220418165707232

    # Buffer常用API介绍

    1. Buffer类及其子类

      classDiagram
      direction BT
      class Buffer
      class ByteBuffer
      class CharBuffer
      class DoubleBuffer
      class FloatBuffer
      class IntBuffer
      class LongBuffer
      class ShortBuffer
      
      ByteBuffer  -->  Buffer 
      CharBuffer  -->  Buffer 
      DoubleBuffer  -->  Buffer 
      FloatBuffer  -->  Buffer 
      IntBuffer  -->  Buffer 
      LongBuffer  -->  Buffer 
      ShortBuffer  -->  Buffer 
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18

      如果图片无法查看,请看这里

      image-20220418174426005

      在NIO中,Buffer是一个顶层父类,他是一个抽象类。常用的缓冲区分别对应byte,char,double,float,int,long,short供7种。

    2. 缓冲区对象创建

      方法名 说明
      static ByteBuffer allocate(长度) 创建byte类型的指定长度的缓冲区
      static ByteBuffer wrap(byte[] array) 创建一个有内容的byte类型的缓冲区

      示例代码

      /**
       * 创建缓冲区
       *
       * @name: CreateBufferDemo
       * @author: terwer
       * @date: 2022-04-18 17:38
       **/
      public class CreateBufferDemo {
          public static void main(String[] args) {
              // 1.创建一个指定长度的缓冲区,ByteBuffer为例
              ByteBuffer byteBuffer = ByteBuffer.allocate(4);
              for (int i = 0; i < 4; i++) {
                  System.out.println(byteBuffer.get());
              }
      
              // 在此调用会报错
              // System.out.println(byteBuffer.get());
              System.out.println("==================");
              System.out.println();
      
              // 2.创建一个有内容的缓冲区
              ByteBuffer wrap = ByteBuffer.wrap("test".getBytes(StandardCharsets.UTF_8));
              for (int i = 0; i < 4; i++) {
                  System.out.println(wrap.get());
              }
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27

      运行结果:

      image-20220418175149177

    3. 缓冲区对象添加数据

      方法名 说明
      Int position()/position(int newPosition) 获取当前要操作的索引/修改当前要操作的索引
      int lkimit()/limit(int newLimit) 最多能操作到哪个索引/修改最多能操作的索引位置
      int capacity() 返回缓冲区的总长度
      int remaining()/boolean hasRemaining() 还有多少能操作的索引个数/是否还能操作
      put (byte b)/put(byte[] src) 添加一个字节/添加字节数组

      image-20220418192657630

      示例代码:

      /**
       * 添加缓冲区
       *
       * @name: PutBufferDemo
       * @author: terwer
       * @date: 2022-04-18 19:27
       **/
      public class PutBufferDemo {
          public static void main(String[] args) {
              // 1.创建一个指定长度的缓冲区
              ByteBuffer byteBuffer = ByteBuffer.allocate(10);
              System.out.println(byteBuffer.position());// 获取当前索引所在的位置
              System.out.println(byteBuffer.limit());// 最多能操作到哪个索引
              System.out.println(byteBuffer.capacity());// 返回缓冲区总长度
              System.out.println(byteBuffer.remaining());// 还有多少个能操作
      
      //        byteBuffer.position(2);
      //        byteBuffer.limit(4);
      //        System.out.println();
      //        System.out.println("============");
      //        System.out.println(byteBuffer.position());// 获取当前索引所在的位置
      //        System.out.println(byteBuffer.limit());// 最多能操作到哪个索引
      //        System.out.println(byteBuffer.capacity());// 返回缓冲区总长度
      //        System.out.println(byteBuffer.remaining());// 还有多少个能操作
      
              // 添加一个字节
              byteBuffer.put((byte) 97);
              System.out.println();
              System.out.println("============");
              System.out.println(byteBuffer.position());// 获取当前索引所在的位置
              System.out.println(byteBuffer.limit());// 最多能操作到哪个索引
              System.out.println(byteBuffer.capacity());// 返回缓冲区总长度
              System.out.println(byteBuffer.remaining());// 还有多少个能操作
      
              // 添加一个字节数组
              byteBuffer.put("test".getBytes(StandardCharsets.UTF_8));
              System.out.println();
              System.out.println("============");
              System.out.println(byteBuffer.position());// 获取当前索引所在的位置
              System.out.println(byteBuffer.limit());// 最多能操作到哪个索引
              System.out.println(byteBuffer.capacity());// 返回缓冲区总长度
              System.out.println(byteBuffer.remaining());// 还有多少个能操作
      
              // 超过缓冲区长度会报错
      //        byteBuffer.put("1234567".getBytes(StandardCharsets.UTF_8));
      //        System.out.println();
      //        System.out.println("============");
      //        System.out.println(byteBuffer.position());// 获取当前索引所在的位置
      //        System.out.println(byteBuffer.limit());// 最多能操作到哪个索引
      //        System.out.println(byteBuffer.capacity());// 返回缓冲区总长度
      //        System.out.println(byteBuffer.remaining());// 还有多少个能操作
      
              // 如果缓冲区满了,可以调整position的位置,会覆盖之前对应索引的值
              byteBuffer.position(0);
              byteBuffer.put("1234567".getBytes(StandardCharsets.UTF_8));
              System.out.println();
              System.out.println("============");
              System.out.println(byteBuffer.position());// 获取当前索引所在的位置
              System.out.println(byteBuffer.limit());// 最多能操作到哪个索引
              System.out.println(byteBuffer.capacity());// 返回缓冲区总长度
              System.out.println(byteBuffer.remaining());// 还有多少个能操作
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
    4. 缓冲区对象读取数据

      方法名 介绍
      flip() 切换读模式,limit设置position位置,position设置0
      get() 读一个字节
      get(byte[] dst) 读多个字节
      get(int index) 读指定索引的字节
      rewind() 将position设置为0,可重复读
      clear() 切换写模式,position设置为0,limit设置为capacity
      array() 将缓冲区转换成字节数组返回

      flip方法:

      image-20220418195006103

      clear方法:

      image-20220418195106115

      示例代码:

      /**
       * 从缓冲区读取数据
       *
       * @name: GetBufferDemo
       * @author: terwer
       * @date: 2022-04-18 19:51
       **/
      public class GetBufferDemo {
          public static void main(String[] args) {
              // 1.创建一个指定长度的缓冲区
              ByteBuffer byteBuffer = ByteBuffer.allocate(10);
              byteBuffer.put("0123".getBytes(StandardCharsets.UTF_8));
              System.out.println("position:" + byteBuffer.position());
              System.out.println("limit:" + byteBuffer.limit());
              System.out.println("capacity:" + byteBuffer.capacity());
              System.out.println("remaining:" + byteBuffer.remaining());
      
              // 切换读模式
              System.out.println();
              System.out.println("=================");
              System.out.println("准备读数据:");
              byteBuffer.flip();
              System.out.println("position:" + byteBuffer.position());
              System.out.println("limit:" + byteBuffer.limit());
              System.out.println("capacity:" + byteBuffer.capacity());
              System.out.println("remaining:" + byteBuffer.remaining());
              for (int i = 0; i < byteBuffer.limit(); i++) {
                  System.out.println(byteBuffer.get());
              }
              // 读取完毕后,继续读取会报错,超过limit
      //        System.out.println(byteBuffer.get());
              // 读取指定字节
      //        System.out.println("读取指定索引:");
      //        System.out.println(byteBuffer.get(2));
      
              System.out.println("读取多个字节:");
              // 重复读取
              byteBuffer.rewind();
              byte[] dst = new byte[4];
              byteBuffer.get(dst);
              System.out.println(new String(dst));
      
              // 将缓冲区转化为字节数组返回
              System.out.println();
              System.out.println("===========");
              System.out.println("将缓冲区转化为字节数组:");
              byte[] array = byteBuffer.array();
              System.out.println(new String(array));
      
              // 切换写模式,会覆盖之前所有的值
              System.out.println();
              System.out.println("================");
              System.out.println("切换写模式,覆盖之前的值:");
              byteBuffer.clear();
              byteBuffer.put("test".getBytes(StandardCharsets.UTF_8));
              System.out.println(new String(byteBuffer.array()));
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58

      注意:

      1. capacity:容量(长度) limit:界限(最多能读/写到哪里) position:位置(读/写哪个索引)
      2. 获取缓冲区的数据之前,要先调用flip()方法,重复读需要调用rewind()方法
      3. 再次写数据之前,需要先调用clear()方法,此时数据还未消失。再次写入数据完成,数据覆盖了才会消失。
    编辑 (opens new window)
    #nio#buffer
    上次更新: 2023/02/22, 13:47:25
    NIO编程及其三大核心原理
    NIO三大核心之通道(Channel)

    ← NIO编程及其三大核心原理 NIO三大核心之通道(Channel)→

    最近更新
    01
    解决css部分border被圆角切掉之后圆角的边框消失问题
    03-18
    02
    使用TypeScript开发一个自定义的Node-js前端开发脚手架
    03-08
    03
    Github-Actions使用release-please实现自动发版
    03-06
    更多文章>
    Theme by Vdoing | Copyright © 2011-2023 Terwer Green | MIT License | 粤ICP备2022020721号-1 | 百度统计
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式