《精通并发与Netty》学习笔记(15 - 详解NIO中Buffer之position,limit,capacity)
一、前言
熟悉NIO的人想必一定不会陌生buffer中position,limit,capacity这三个属性吧,之前在学习的时候遇到一个问题:就是当你先往缓冲区写入一部分数据,然后调用flip()方法,再全部读取完数据,然后再调用flip()方法,此时这三个值的变化是怎样的,研究了一下,决定写下来分享一下。
二、正文
1、介绍
position: 它指的是下一次读取或写入的位置。
limit: 指定还有多少数据需要写出(在从缓冲区写入通道时),或者还有多少空间可以读入数据(在从通道读入缓冲区时),它初始化是与capacity的值一样,当调用flip()方法之后,它的值会改变成position的值,而position被置0。它箭头所指的位置是最后一位元素的下一位所在的位置*
capacity: 指定了可以存储在缓冲区中的最大数据容量,实际上,它指定了底层数组的大小,或者至少是指定了准许我们使用的底层数组的容量,这个初始化后就不会再改变了。
2、图示
以上三个属性值之间有一些相对大小的关系:0 <= position <= limit <= capacity。如果我们创建一个新的容量大小为7的ByteBuffer对象,在初始化的时候,position设置为0,limit和 capacity被设置为7,在以后使用ByteBuffer对象过程中,capacity的值不会再发生变化,而其它两个个将会随着使用而变化。三个属性值分别如图所示:
初始化:
假设我们现在要往这个缓冲区里面写入3个字节,写完之后,position的箭头就会指向3的位置,而limit不变:
此时我们想从缓冲区读取这3个字节,就必须调用flip()方法,调用了flip()方法过后,limit置为position的位置,而position被置为0,也正应证了上面所说的,position它指的是下一次读取或写入的位置,limit它箭头所指的位置是最后一位元素的下一位所在的位置:
现在我们可以调用get()方法,一直从缓冲区里面取数据,直到取完为止,也就是当position与limit的值一样时,就取完了:
这一次简单的读写操作就完成了,如果想恢复成初始状态的话,可以调用clear()方法:
之前学到这里的时候有个疑问,不知道大家想过没有,就是我们在调用了get()方法从缓冲区取完里面的数据,立马去调用flip()方法,那这三个属性的值会是什么变化?如果当我只读了2个字节的数据之后,就不读了,然后再去调用flip(),这三个值又会是怎么变化?其实不管怎么绕,你只要懂得原理,就不难,咱们先看flip()源代码做了什么:
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
这里不难发现,调用flip()方法,无非就是给这几个变量赋值,将当前的position值赋给limit,然后将position的值置为0,Mark是一个标志变量,咱们以后会提到。熟悉以上代码就不难解决我提出的2个问题:
当你读取完调用flip()的方法 positon:0 limit:3 capacity:7
当你读取2个字节之后调用flip()方法 positon:0 limit:2 capacity:7
这里就解决了我之前遇到的这三个属性值变化的问题!!!
三、测试代码
读取完调用flip:
package com.cing.nio; import java.io.FileInputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; public class NioTest1 {
public static void main(String[] args) throws Exception{ FileInputStream fis = new FileInputStream("D:\\A.txt");
FileChannel fc = fis.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(7);
output("初始化", buffer); fc.read(buffer);
output("调用READ方法", buffer); buffer.flip();
output("第一次调用flip", buffer); while (buffer.remaining() > 0) {
byte b = buffer.get();
}
output("get()", buffer); buffer.flip();
output("第二次flip", buffer); fis.close();
} public static void output(String step, Buffer buffer) {
System.out.println(step + " : ");
System.out.println("buffer: " + buffer + ", ");
}
}
输出结果为:
初始化 :
buffer: java.nio.HeapByteBuffer[pos=0 lim=7 cap=7],
调用READ方法 :
buffer: java.nio.HeapByteBuffer[pos=3 lim=7 cap=7],
第一次调用flip :
buffer: java.nio.HeapByteBuffer[pos=0 lim=3 cap=7],
get() :
buffer: java.nio.HeapByteBuffer[pos=3 lim=3 cap=7],
第二次flip :
buffer: java.nio.HeapByteBuffer[pos=0 lim=3 cap=7],
读取2字节之后调用flip:
package com.cing.nio; import java.io.FileInputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; public class NioTest1 {
public static void main(String[] args) throws Exception{ FileInputStream fis = new FileInputStream("D:\\A.txt");
FileChannel fc = fis.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(7);
output("初始化", buffer); fc.read(buffer);
output("调用READ方法", buffer); buffer.flip();
output("第一次调用flip", buffer); while (buffer.remaining() > 1) {
byte b = buffer.get();
}
output("get()", buffer); buffer.flip();
output("第二次flip", buffer); fis.close();
} public static void output(String step, Buffer buffer) {
System.out.println(step + " : ");
System.out.println("buffer: " + buffer + ", ");
}
}
输出结果为:
初始化 :
buffer: java.nio.HeapByteBuffer[pos=0 lim=7 cap=7],
调用READ方法 :
buffer: java.nio.HeapByteBuffer[pos=3 lim=7 cap=7],
第一次调用flip :
buffer: java.nio.HeapByteBuffer[pos=0 lim=3 cap=7],
get() :
buffer: java.nio.HeapByteBuffer[pos=2 lim=3 cap=7],
第二次flip :
buffer: java.nio.HeapByteBuffer[pos=0 lim=2 cap=7],
《精通并发与Netty》学习笔记(15 - 详解NIO中Buffer之position,limit,capacity)的更多相关文章
- C++并发与多线程学习笔记--unique_lock详解
unique_lock 取代lock_quard unique_lock 的第二个参数 std::adopt_lock std::try_to_lock std::defer_lock unique_ ...
- C++并发与多线程学习笔记--参数传递详解
传递临时对象 陷阱 总结 临时对象作为线程参数 线程id的概念 临时对象构造时的抓捕 成员函数指针做线程函数 传递临时对象作为线程参数 创建的工作线程不止一个,线程根据编号来确定工作内容.每个线程都需 ...
- Angular6 学习笔记——组件详解之组件通讯
angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...
- Angular6 学习笔记——组件详解之模板语法
angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...
- Angular6 学习笔记——路由详解
angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...
- [原创]java WEB学习笔记55:Struts2学习之路---详解struts2 中 Action,如何访问web 资源,解耦方式(使用 ActionContext,实现 XxxAware 接口),耦合方式(通过ServletActionContext,通过实现 ServletRequestAware, ServletContextAware 等接口的方式)
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- JavaScript学习笔记-实例详解-类(二)
实例详解-类(二) //===给Object.prototype添加只读\不可枚举\不可配置的属性objectId(function(){ Object.defineProperty(Object ...
- JavaScript学习笔记-实例详解-类(一)
实例详解-类(一): //每个javascript函数(除了bind())都自动拥有一个prototype对象// 在未添加属性或重写prototype对象之前,它只包含唯一一个不可枚举属性const ...
- Android学习笔记-Dialog详解
1.对话框的使用 1.1AlertDialog的显示 简单对话框以及监听的设置:重点掌握三个按钮(也就是三上单词): PositiveButton(确认按钮);NeutralButton(忽略按钮) ...
随机推荐
- Charles----伪造手机端的request和reponse参数
使用场景: 在测试中通过伪造reponse数据来模拟某些测试场景,如下截图.要求:通过修改reponse中的值,再次请求修改7为100,只是会显示为99+ 实现方式: 1.通过breakpoints来 ...
- python中的数据类型(二)
一.列表(list) 列表是可变的,有序的(只要能索引的都是有序的) 列表的基本操作: 1.增 1.append 追加 例:lst.append(8) print (ls ...
- 数组增、删方法(push()-unshift()-pop()和shift())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- tap 事件会触发两次问题
因项目中使用 coffeeScript (http://coffee-script.org/),此处记录下用 coffeeScript 语法解决 tap 事件触发两次的问题. 在 id="b ...
- 使用sysbench对MySQL进行压力测试
1.背景 出自percona公司,是一款多线程系统压测工具,可以根据影响数据库服务器性能的各种因素来评估系统的性能.例如,可以用来测试文件IO,操作系统调度器,内存分配和传输速度,POSIX线程以及 ...
- 重新梳理一下adb操作app(golang版)
主要参考我之前整理的内容https://www.cnblogs.com/pu369/p/10490668.html,梳理简化一下思路,以便于用最简单的代码来应对无聊人士的要求. 需求主要是:打开手机. ...
- UVA 11754 Code Feat 中国剩余定理+枚举
Code FeatUVA - 11754 题意:给出c个彼此互质的xi,对于每个xi,给出ki个yj,问前s个ans满足ans%xi的结果在yj中有出现过. 一看便是个中国剩余定理,但是同余方程组就有 ...
- 报错 One or more constraints have not been satisfied.
常出现在导入已有标签时. 需要在<build/><plugins/>里面追加标签 <plugin> <groupId>org.apache.maven. ...
- 集合家族——stack
一.概述 在 Java 中 Stack 类表示后进先出(LIFO)的对象堆栈.栈是一种非常常见的数据结构,它采用典型的先进后出的操作方式完成的 它通过五个操作对类 Vector 进行了扩展 ,允许将向 ...
- ZR#996
ZR#996 解法: 若删除长度为 $ x $ 的子串后序列中没有相同元素,那么一定有至少一个长度为 $ x+1 $ 的子串,删除它后序列中也没有相同元素. CODE: #include <io ...