中国做视频网站有哪些,阿里巴巴建设电子商务网站目的,网站的根目录怎么找,缤纷销客crm引言
缓冲区是一个用于特定基本类型的容器。由java.nio 包定义#xff0c;所有缓冲区都是 Buffer 抽象类的子类。 Java NIO 中的 Buffer #xff0c;主要用于与NIO 通道进行交互。数据从通道存入缓冲区#xff0c;从缓冲区取出到通道中。
一、创建缓冲区
缓冲区的本质是 …引言
缓冲区是一个用于特定基本类型的容器。由java.nio 包定义所有缓冲区都是 Buffer 抽象类的子类。 Java NIO 中的 Buffer 主要用于与NIO 通道进行交互。数据从通道存入缓冲区从缓冲区取出到通道中。
一、创建缓冲区
缓冲区的本质是 数组 用于存储不同类型的数据根据数据类型boolean 除外提供了相应类型的缓冲区如ByteBuffer、IntBuffer等。这些缓冲区的管理方式都是类似的都是通过 allocate() 方法指定容量并创建缓冲区。
// 创建一个 1 KB 大小的缓冲区
ByteBuffer buf ByteBuffer.allocate(1024);
一般情况下我们通过 allocate() 方法创建缓冲区但是在需要高性能的地方有时候往往需要使用 allocateDirect() 方法。
allocate() 创建非直接缓冲区allocateDirect() 创建直接缓冲区。
二、缓冲区的四个核心属性
缓冲区的本质实际上是一个数组最常用的ByteBuffer本身就是一个 byte[] 数组根据数据读取的场景设计者为Buffer 设置了四个核心属性定义在 Buffer 抽象类中
private int mark -1;
private int position 0;
private int limit;
private int capacity;
缓冲区的操作实际上是借由这四个 int 标记来完成的可以理解为抽象的指针。它们的关系如下 0 mark position limit capacity position 表示位置表示当前程序正在操作的数据的下一个索引值。 mark 表示标记通过 mark() 方法记录当前数据的索引。可以通过 reset() 重新找到 mark 所指向的数据。 limit 界限表示缓冲区中可以操作数据的大小limit 后的数据不能进行读写。 capacity 缓冲区容量因为缓冲区本身就是数组因此一旦声明不能改变该值。 2.1 初始的指针状态
假设我们声明了一个 capacity 为 5 的字节缓冲区
ByteBuffer buf ByteBuffer.allocate(5);
那么缓冲区的初始状态就是如下图所示 2.2 当缓冲区中有数据的状态
由于缓冲区独特的构造在读和写的时候limit 与 position 指针是有一定区别的。
// 写模式
byteBuffer.put(Tom.getBytes()); // 读模式
byteBuffer.get(); 三、缓冲区的核心方法
3.1 存取数据
缓冲区既然作为数据的容器必然涉及到数据的存取操作但要注意存和取操作不可以连续执行两个动作之间需要有一个 “翻转” 的操作。
put() 方法将数据放入到缓冲区中get() 方法从缓冲区中取出数据。
3.2 flip()翻转、rewind()倒带、clear()清空 flip() : 翻转将缓冲区进行读写切换。 rewind() : 倒带可以将 position 和 limit 回退到上一次操作前。 clear() 清空缓冲区官方说明是“clears the buffer”但详细解释是将 position 和 limit 恢复“出厂设置”并丢弃 mark。注意缓冲区中的数据并非清空只是将两个指针重置数据处在一种“被遗忘”状态如果进行 get()操作依然可以取出。同时clear 执行之后的缓冲区无法通过 rewind() 回退指针。 3.3 mark()标记、reset()定位 mark()方法可以记录当前 position 的位置并可以通过 reset() 方法恢复到 mark() 3.4 hasRemaining()是否有未读数据、remaining()获取未读数据数量 hasRemaining() 用于判断读模式下的 Buffer 中是否还有未读数据 remaining() 方法可以返回剩余可操作的元素个数。其值与 limit - position 的差值相等。 3.5 示例程序
从一开始创建一个 Buffer 开始通过存入、读取数据来观察各个属性capacity、limit、position、mark 等的变化。
创建
// 分配 1 KB 大小的缓冲区
ByteBuffer byteBuffer ByteBuffer.allocate(1024);
System.out.println(allocate());
System.out.println(position byteBuffer.position());
System.out.println(limit byteBuffer.limit());
System.out.println(capacity byteBuffer.capacity()); 存数据
System.out.println(put());
String name abcde;
byteBuffer.put(name.getBytes());
System.out.println(position byteBuffer.position());
System.out.println(limit byteBuffer.limit());
System.out.println(capacity byteBuffer.capacity()); 反转
System.out.println(flip());
byteBuffer.flip();
System.out.println(position byteBuffer.position());
System.out.println(limit byteBuffer.limit());
System.out.println(capacity byteBuffer.capacity()); 读数据
System.out.println(get());
byte[] dst new byte[byteBuffer.limit()];
byteBuffer.get(dst);
System.out.println(position byteBuffer.position());
System.out.println(limit byteBuffer.limit());
System.out.println(capacity byteBuffer.capacity());
System.out.println(new String(dst)); 倒带
System.out.println(rewind());
byteBuffer.rewind();
System.out.println(position byteBuffer.position());
System.out.println(limit byteBuffer.limit());
System.out.println(capacity byteBuffer.capacity()); 清空
System.out.println(clear());
byteBuffer.clear();
System.out.println(position byteBuffer.position());
System.out.println(limit byteBuffer.limit());
System.out.println(capacity byteBuffer.capacity()); 标记、定位标记
ByteBuffer buf ByteBuffer.allocate(5);
buf.put(abcde.getBytes());
buf.flip();
byte[] dst new byte[buf.limit()];
buf.get(dst, 0, 2); // get(byte[] dst, int offset, int length)
System.out.println(第一次取出结果 new String(dst));
System.out.println(position buf.position());
// mark()标记
buf.mark();
buf.get(dst, 2, 2); // get(byte[] dst, int offset, int length)
System.out.println(第二次取出结果 new String(dst));
System.out.println(position buf.position());
// 恢复到mark
buf.reset();
System.out.println(reset 恢复到 mark 位置);
System.out.println(position buf.position()); 查询剩余数据
// remaining() 获取缓冲区中还可以操作的数量
if (buf.hasRemaining()) {System.out.println(buf.remaining());System.out.println(limit - position (buf.limit() - buf.position()));
} 四、直接缓冲区与非直接缓冲区
字节缓冲区要么是 直接缓冲区要么是 非直接缓冲区。
非直接缓冲区属于常规操作传统的 IO 流和 allocate() 方法分配的缓冲区都是非直接缓冲区建立在 JVM 内存中。这种常规的非直接缓冲区会将内核地址空间中的内容拷贝到用户地址空间中间缓冲区后再由程序进行读或写操作换句话说磁盘上的文件在与应用程序交互的过程中会在两个缓存中来回进行复制拷贝。
而直接缓冲区绝大多数情况用于显著提升性能缓冲区直接建立在物理内存相对于JVM 的内存空间中省去了在两个存储空间中来回复制的操作可以通过调用 ByteBuffer 的 allocateDirect() 工厂方法来创建。直接缓冲区中的内容可以驻留在常规的垃圾回收堆之外因此它们对应用程序的内存需求量造成的影响可能并不明显。另外直接缓冲区还可以通过 FileChannel 的 map() 方法将文件直接映射到内存中来创建该方法将返回 MappedByteBuffer 。
直接或非直接缓冲区只针对字节缓冲区而言。字节缓冲区是那种类型可以通过 isDirect() 方法来判断。 注意直接缓冲区性能虽然好但是缓冲区直接建立在物理内存中无法由 GC来释放可控性差同时分配和销毁成本很高在对性能不是特别依赖的场景不建议使用