前言

上篇【从入门到放弃-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为当前positionmark = position;return this;
}

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

reset

public Buffer reset() {int m = mark;if (m < 0)throw new InvalidMarkException();//设置position为当前markposition = m;return this;
}

回到之前设置mark的位置

clear

public Buffer clear() {//设置position为0position = 0;//limit设置为capacity大小limit = capacity;//mark设置为-1(初始化)mark = -1;return this;
}

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

flip

public Buffer flip() {//limit设置为当前位置limit = position;//position设置为0position = 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】并发编程-NIO-Buffer相关推荐

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

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

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

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

  3. 操作系统锁的实现方法有哪几种_「从入门到放弃-Java」并发编程-锁-synchronized...

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

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

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

  5. 【从入门到放弃-Java】并发编程-线程安全

    概述 并发编程,即多条线程在同一时间段内"同时"运行. 在多处理器系统已经普及的今天,多线程能发挥出其优势,如:一个8核cpu的服务器,如果只使用单线程的话,将有7个处理器被闲置, ...

  6. 《Java并发编程入门与高并发面试》or 《Java并发编程与高并发解决方案》笔记

    <Java并发编程入门与高并发面试>or <Java并发编程与高并发解决方案>笔记 参考文章: (1)<Java并发编程入门与高并发面试>or <Java并发 ...

  7. 学习笔记:Java 并发编程①_基础知识入门

    若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 视频下载: ...

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

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

  9. java并发编程入门_探讨一下!Java并发编程基础篇一

    Java并发编程想必大家都不陌生,它是实现高并发/高流量的基础,今天我们就来一起学习这方面的内容. 什么是线程?什么是进程?他们之间有什么联系? 简单来说,进程就是程序的一次执行过程,它是系统进行资源 ...

最新文章

  1. 关于mysql archive存储引擎-专门存储审计和日志数据
  2. golang源码分析:defer流程分析
  3. Fabric架构演变之路 1
  4. Spring Boot休眠提示
  5. 网络爬虫--24.【selenium实战】实现拉勾网爬虫之--分析接口获取数据
  6. matlab disteclud,机器学习实战ByMatlab(3)K-means算法
  7. 重构随笔——重构的原则
  8. 如何利用FL Studio中文版做出失真效果
  9. Linux编译安装PHP Mysql Nginx
  10. python文件中执行py文件
  11. 时代杂志评选了08年50个最棒的网站
  12. 如何写数学建模竞赛论文
  13. 求职类App原型制作分享-Part-time Clouds
  14. 利用MSXSL.exe绕过AppLocker应用程序控制策略
  15. CAN通信----电路图
  16. eclipse发生了错误,请参阅日志文件怎么办呀
  17. 【删库跑路】使用Binlog日志恢复误删的MySQL数据
  18. 学计算机学体育生闺女,适合女孩学的体育项目
  19. 门店如何利用会员系统软件做精细化运营管理
  20. 云原生CI/CD:tekton/pipeline之认证篇

热门文章

  1. 配置中心_Nacos做配置中心
  2. 期刊投稿状态_追踪期刊在线系统投稿状态(十七)
  3. 超级计算机游戏电脑,Salad邀请PC玩家参与全球最大分布式超级计算机的构建
  4. vue 渲染函数处理slot_vue render 渲染函数
  5. 【LeetCode笔记】300. 最长递增子序列(Java、动态规划、二分法、贪心)
  6. 【LeetCode笔记】287. 寻找重复数(Java、快慢指针、原地、链表)
  7. 论文页眉奇偶页不同怎么设置_怎样设置Word页眉页脚奇偶页不同?
  8. python while true_Python天坑系列(一):while 1比while True更快?
  9. es6删除数组某一项_精学手撕系列——数组扁平化
  10. java版的中世纪战争_世界战争英雄设置-火焰纹章英雄英雄地图及AI命令设置