Netty开篇——NIO章上(三)

Java NIO基本介绍

  1. java non-blocking I/O 称为NIO(也叫New IO)。JDK4开始提供,同步非阻塞
  2. 相关内容在 java.nio 包及子包下,对java.io 包中的很多类进行改写。
  3. 三大核心: Channel(通道),Buffer(缓冲区),Selector(选择器)
  4. NIO是面向缓冲区或者面向块 编程 。数据读取到一个它后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使用它可以提供非阻塞式的高伸缩性网络
  5. NIO的非阻塞模式,使一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据可以读取之前,该线程可以继续做其他的事情。
  6. 通俗理解: NIO 是可以做到用一个线程来处理多个操作。假设有 10000 个请求过来,根据实际情况,可以分配50 或者 100 个线程来处理。不像之前的阻塞IO 那样,非得分配 10000 个。
  7. HTTP2.0 使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比 HTTP1.1 大了好几个数量级
  8. 基本案例:

NIO 和 BIO 的比较

  1. BIO以流的方式处理数据,而NIO以块的方式处理数据,I/O块的效率比I/O流高很多
  2. BIO 是阻塞的,NIO则是非阻塞的
  3. BIO 基于字节流和字符流进行操作,而NIO基于Channel(通道)和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector 选择器用于监听多个通道的事件(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道

Selector、Channel 和 Buffer 的关系图

  1. 每个channel都会对应一个Buffer
  2. 一个Selector对应一个线程
  3. 多个channel会注册到其selector
  4. Selector会根据不同的Event,在各个Channel上切换
  5. channel 是双向的,可以返回底层操作系统的情况,比如Linux,底层的操作系统通道就是双向的.
  6. Buffer是一个内存块,底层是一个数组
  7. 数据的读取写入是通过 Buffer,这个和BIO有所区别,BIO 中要么是输入流,或者是输出流,不能双向,但是NIO的Buffer是可以读也可以写,需要flip()切换

缓冲区(Buffer)

  1. Buffer本质上是一个可以读写数据的内存块,可以理解成是一个容器对象(含数组),该对象提供了一组方法,可以更轻松地使用内存块,Buffer对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。Channel 读写的数据都必须经由Buffer

  2. Buffer是父类、抽象类,类的层级关系图

  3. 常用Buffer子类

    • ByteBuffer 存储字节数据到缓冲区
    • shortBuffer 存储字符串数据到缓冲区
    • CharBuffer 存储字符数据到缓冲区
    • IntBuffer 存储整数数据到缓冲区
    • LongBuffer 存储长整型教据到缓冲区
    • DoubleBuffer 存储小数到缓冲区
    • FloatBuffer 存储小数到缓冲区
  4. 这些Buffer都把数据存于自己类型的数组

  5. Buffer类的四个属性:

    • Capacity:容量,即可以容纳的最大数据量;在缓冲区创建时被设定并且不能改变
    • Limit:表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写操作。且极限是可以修改的
    • Position:位置,下一个要被读写的元素的索引,每次读写缓冲区数据时都会改变改值,为下次读写做准备
    • Mark:标记

Buffer类相关方法

java 复制代码
public abstract class Buffer{
//JDK1.4时,引入的api
public final int capacity()//返回此缓冲区的容量
public final int position()//返回此缓冲区的位置
public final Buffer position(int newPositio)//设置此缓冲区的位置
public final int limit()//返回此缓冲区的限制
public final Buffer limit(int newLimit)//设置此缓冲区的限制
public final Buffer mark()//在此缓冲区的位置设置标记
public final Buffer reset()//将此缓冲区的位置重置为以前标记的位置
public final Buffer clear()//清除此缓冲区,即将各个标记恢复到初始状态,但是数据并没有真正擦除,
public final Buffer flip()//反转此缓冲区
public final Buffer rewind()//重绕此缓冲区
public final int remaining()//返回当前位置与限制之间的元素数
public final boolean hasRemaining()//告知在当前位置和限制之间是否有元素
public abstract boolean isReadOnly()://告知此缓冲区是否为只读缓冲区
//JDK1.6时引入的api
public abstract boolean hasArray();//告知此缓冲区是否具有可访问的底层实现数组
public abstract Object array();//返回此缓冲区的底层实现数组
public abstract int arrayOffset();/返回此缓冲区的底层实现数组中第一个缓冲区元素的偏移量
public abstract boolean is Direct();//告知此缓冲区是否为直接缓冲区
}

ByteBuffer

  1. 除了boolean,其他基本类型都有一个Buffer类型与之相对应,最常用的自然是 ByteBuffer 类(二进制数据),该类的主要方法如下:
java 复制代码
public abstract class ByteBuffer(
//缓冲区创建相关api
public static ByteBuffer allocateDirect(int capacity)//创建直接缓冲区
public static ByteBuffer allocate(int capacity)//设置缓冲区的初始容量
public static ByteBuffer wrap(byte[] array)//把一个数组放到缓冲区中使用
//构造初始化位置offset和上界length的缓冲区
public static ByteBuffer wrap(byte[] array,int offset, int length)
//缓存区存取相关API
public abstract byte get()//从当前位置position上get,get之后,position会自动+1 
public abstract byte get(int index);//从绝对位置get
public abstract ByteBuffer put(byte b);//从当前位置上添加,put之后,position会自动+1 
public abstract ByteBuffer put(int index,byte b);//从绝对位置上put

关于Buffer的注意事项和细节

  1. ByteBuffer支持类型化的put和get,数据类型必须保持一致,否则可能有 BufferUnderflowException 异常。
  2. Buffer支持转换为只读buffer,调用asReadOnlyBuffer()
  3. NIO还提供了MappedByteBuffer,可以让文件直接在内存(堆外内存) 中进行修改,而如何同步到文件由NIO来完成.
  4. NIO还支持通过多个Buffer(buffer数组)完成读写操作即 Scattering(分散)和 Gathering(合并)
相关推荐
Java牛马2 小时前
SpringBoot Starter 依赖相关总结
java·spring·springboot·starter·自动装配·依赖
吴声子夜歌2 小时前
Java面试——Spring Cloud原理及应用(二)
java·spring cloud·面试
东小西3 小时前
【SAA实战】第 1 篇:ReactAgent 入门——先撸个"会调工具的助手"跑起来
java·人工智能·spring
mqiqe3 小时前
AgentScope Java 2.0 协议集成全景解析:A2A、AG-UI、Agent Protocol 三大开放协议实战指南
java·开发语言·ui
脉动数据行情3 小时前
Java 实现台股 TWSE/TPEx 行情采集(个股 + K 线)
java·开发语言·twse·tpex·台股
月华路5 小时前
G1 GC 对数组与大对象(Humongous)的处理
java·jvm·算法
liangshanbo12156 小时前
虚拟列表深度面试题整理
java·开发语言·前端
gugucoding6 小时前
59. 【Java】Spring Boot 入门:第一个 Web 应用
java·开发语言·spring boot
10mAh7 小时前
【Java】HashMap 的 put 到底做了什么?——冲突、扩容与树化实测
java·开发语言·hash
我命由我123457 小时前
人脸识别 - 勒克斯(光线照射到物体表面上的明亮程度)
android·java·学习·java-ee·人脸识别·学习方法·android runtime