前言

上篇【从入门到放弃-Java】并发编程-NIO-Channel中我们学习到channel是双向通道,数据通过channel在实体(文件、socket)和缓冲区(buffer)中可以双向传输。

本文我们就来学习下buffer

简介

buffer即缓冲区,实际上是一块内存,可以用来写入、读取数据。是一个线性的、大小有限的、顺序承载基础数据类型的内存块。

buffer有三个重要的属性:

capacity:缓冲池大小,是不可变的。当buffer写满时,需要先清空才能继续写入。

limit:是buffer中不可以被读或者写的第一个元素的位置,limit的大小永远不会超过capacity(在写模式下,limit等于capacity)

position:是buffer中可以被读或者写的第一个元素的位置,position的大小永远不会超过limit

除了boolean外,每一个基础数据类型都有对应的buffer。如:ByteBuffer、CharBuffer、LongBuffer等

buffer不是线程安全的,如果要在多线程中使用 需要加锁控制

接下来以ByteBuffer为例开始学习。

ByteBuffer

allocateDirect

public static ByteBuffer allocateDirect(int capacity) {

//会创建一个容量大小为capacity的DirectByteBuffer(ByteBuffer的子类)

return new DirectByteBuffer(capacity);

}

allocate

public static ByteBuffer allocate(int capacity) {

if (capacity < 0)

throw createCapacityException(capacity);

//会创建一个容量大小为capacity的HeapByteBuffer(ByteBuffer的子类)

return new HeapByteBuffer(capacity, capacity);

}

HeapByteBuffer和DirectByteBuffer的区别:

DirectByteBuffer是直接调用native方法在本机os::malloc()创建堆外内存;HeapByteBuffer是直接在jvm的堆中分配内存。

当buffer中的数据和磁盘、网络等的交互都在操作系统的内核中发生时,使用DirectByteBuffer能避免从内核态->用户态->内核态的切换开销,所有的处理都在内核中进行,性能会比较好

当频繁创建操作数据量比较小的buffer时,使用HeapByteBuffer在jvm堆中分配内存能抵消掉使用DirectByteBuffer带来的好处。

wrap

public static ByteBuffer wrap(byte[] array,

int offset, int length)

{

try {

return new HeapByteBuffer(array, offset, length);

} catch (IllegalArgumentException x) {

throw new IndexOutOfBoundsException();

}

}

public static ByteBuffer wrap(byte[] array) {

return wrap(array, 0, array.length);

}

将byte数组包装成一个ByteBuffer

读数据

使用get方法从Buffer中读取数据

从Buffer中读取数据到Channel即:Channel::write() (从buffer中读取数据写入到资源中,所以是write)

写数据

使用put方法直接设置Buffer中的数据

从Channel中读取数据到Buffer即:Channel::read() (从资源中读取数据写入到buffer中,所以是read)

position

//获取buffer中当前position的位置

public final int position() {

return position;

}

//设置buffer的position为newPosition,注意newPosition要大于0且小于limit,如果remark大于newPosition则设置为-1

public Buffer position(int newPosition) {

if (newPosition > limit | newPosition < 0)

throw createPositionException(newPosition);

position = newPosition;

if (mark > position) mark = -1;

return this;

}

limit

//获取buffer中当前limit的位置

public final int limit() {

return limit;

}

//设置buffer的limit为newLimit,注意newLimit要大于0且小于capacity。如果position大于newLimit这设置为newLimit,如果remark大于newLimit则设置为-1

public Buffer limit(int newLimit) {

if (newLimit > capacity | newLimit < 0)

throw createLimitException(newLimit);

limit = newLimit;

if (position > limit) position = limit;

if (mark > limit) mark = -1;

return this;

}

mark

public Buffer mark() {

//标记mark为当前position

mark = position;

return this;

}

将当前位置做标记,在使用reset方法时,可以回到当前mark的位置

reset

public Buffer reset() {

int m = mark;

if (m < 0)

throw new InvalidMarkException();

//设置position为当前mark

position = m;

return this;

}

回到之前设置mark的位置

clear

public Buffer clear() {

//设置position为0

position = 0;

//limit设置为capacity大小

limit = capacity;

//mark设置为-1(初始化)

mark = -1;

return this;

}

读取完数据后调用clear,即将buffer逻辑上清空了,可以从0开始写入数据

flip

public Buffer flip() {

//limit设置为当前位置

limit = position;

//position设置为0

position = 0;

//mark设置为-1(初始化)

mark = -1;

return this;

}

将buffer从写模式设置为读模式,limit设置为当前position的位置,即只能读取limit大小的数据

rewind

public Buffer rewind() {

position = 0;

mark = -1;

return this;

}

将position设置为0,即从头开始读取

remaining

public final int remaining() {

return limit - position;

}

返回buffer中还有多少byte是未读的

hasRemaining

public final boolean hasRemaining() {

return position < limit;

}

是否已读完

compact

public ByteBuffer compact() {

System.arraycopy(hb, ix(position()), hb, ix(0), remaining());

position(remaining());

limit(capacity());

discardMark();

return this;

}

将position和limit直接的数据copy到byteBuffer的起始处,将已读数据清空,并将新的position设置为当前未读数据的末尾。这样能避免clear方法会将未读数据也清空的问题

slice

public ByteBuffer slice() {

return new HeapByteBufferR(hb,

-1,

0,

this.remaining(),

this.remaining(),

this.position() + offset);

}

ByteBuffer slice(int pos, int lim) {

assert (pos >= 0);

assert (pos <= lim);

int rem = lim - pos;

return new HeapByteBufferR(hb,

-1,

0,

rem,

rem,

pos + offset);

}

新创建一个ByteBuffer,将缓存区分片,设置一个子缓冲区,实际上内存还是共享的,数据发生改变,两个缓冲区读取的数据都会是改变后的。

总结

Buffer最重要的三个属性:position、limit、capacity。牢记这三个属性的含义及读写切换时,设置值是如何变化的,Buffer的核心知识点就掌握了。

原文链接

本文为云栖社区原创内容,未经允许不得转载。

阿里云 刷新缓存 java_【从入门到放弃-Java】并发编程-NIO-Buffer相关推荐

  1. 阿里云“7天实践训练营”入门班第二期学习笔记 第五天 在线编程挑战

    阿里云"7天实践训练营"入门班第二期学习笔记 第五天 在线编程挑战 吾辈,完全不会编程 以下内容全程来自阿里云社区的大佬分析讲解 原题目 知识点:搜索.字符串.位运算 有一天Jer ...

  2. ace缓存扩展接口_Laravel框架怎样使用阿里云ACE缓存服务

    之前我写了一篇在 Laravel 4 框架中使用阿里云 OCS 缓存的文章.介绍了怎样通过扩展 Laravel 4 来支持须要 SASL 认证的阿里云 OCS 缓存服务.有网友问我.ACE 的缓存怎么 ...

  3. ace缓存扩展接口_Laravel框架中实现使用阿里云ACE缓存服务

    之前我写了一篇在 Laravel 4 框架中使用阿里云 OCS 缓存的文章,介绍了如何通过扩展 Laravel 4 来支持需要 SASL 认证的阿里云 OCS 缓存服务.有网友问我,ACE 的缓存怎么 ...

  4. 阿里云天池龙珠计划SQL入门与实践 | Task02 SQL基础查询与排序

    本文为阿里云天池学习<SQL入门与实践>第二讲学习笔记,同时该讲内容基于<SQL基础教程>第二章(查询基础)及第三章(聚合与排序). SQL基础查询与排序 一.SELECT语句 ...

  5. 【从入门到放弃-Java】并发编程-NIO-Buffer

    前言 上篇[从入门到放弃-Java]并发编程-NIO-Channel中我们学习到channel是双向通道,数据通过channel在实体(文件.socket)和缓冲区(buffer)中可以双向传输. 本 ...

  6. Java并发编程(中下篇)从入门到深入 超详细笔记

    接上一篇博客笔记:Java并发编程(中上篇)从入门到深入 超详细笔记_未来很长,别只看眼前的博客-CSDN博客https://blog.csdn.net/weixin_53142722/article ...

  7. 基于JVM原理、JMM模型和CPU缓存模型深入理解Java并发编程

    许多以Java多线程开发为主题的技术书籍,都会把对Java虚拟机和Java内存模型的讲解,作为讲授Java并发编程开发的主要内容,有的还深入到计算机系统的内存.CPU.缓存等予以说明.实际上,在实际的 ...

  8. 【从入门到放弃-Java】并发编程-锁-synchronized

    简介 上篇[从入门到放弃-Java]并发编程-线程安全中,我们了解到,可以通过加锁机制来保护共享对象,来实现线程安全. synchronized是java提供的一种内置的锁机制.通过synchroni ...

  9. 【从入门到放弃-Java】并发编程-NIO-Channel

    前言 上篇[[从入门到放弃-Java]并发编程-NIO使用]()简单介绍了nio的基础使用,本篇将深入源码分析nio中channel的实现. 简介 channel即通道,可以用来读.写数据,它是全双工 ...

最新文章

  1. 2022-2028年中国香精香料行业投资分析及前景预测报告
  2. 使用KNN模型进行多标签分类实战(Multilabel Classification)
  3. 解决Win10下_findnext()异常
  4. java中substring函数
  5. mysql SQLyog导入导出csv文件
  6. 在java中使用关键字导入包_java中import关键字的使用方法
  7. 开发移动端web页面click事件失效问题
  8. mlp神经网络_白天鹅黑天鹅灰天鹅?卷积神经网络帮你搞定识别
  9. go kegg_工具篇丨GO和KEGG富集不到通路?快试试这个超赞的功能分析工具吧
  10. linux的硬件系统管理,Linux 系统硬件管理的基础知识(四)
  11. 【内存模型和名称空间】——C++ Prime Plus CH9
  12. 【运动控制】经典控制理论——PID控制
  13. 数字舵机和模拟舵机的区别
  14. 命令行 - 很好的工具,很强大
  15. win7定时关机命令_磨刀三分钟 | 以【设置定时关机】为例,学会计算机界的如来神掌第1式...
  16. 微分中值定理之柯西中值定理
  17. 用PowerPoint巧做特效字幕(转)
  18. 片上网络之路由器微结构
  19. 阿里云域名解析与绑定过程
  20. 吸烟者问题——进程同步

热门文章

  1. C#8.0可空引用类型的使用注意要点
  2. 小程序-wx:for
  3. [leetcode-412-Fizz Buzz]
  4. Powershell AWS 自动化管理 (6) - IAM
  5. hdu 1087 Super Jumping! Jumping! Jumping!
  6. jQuery操作json
  7. Android activity 参数传递
  8. mysql更新日志问题
  9. 网络发展的模式之一:新功能在应用系统涌现,然后逐渐迁移到基础设施
  10. Everyday a English