最近在项目中,频繁使用到ByteBuffer,对于其中的一些用法感到迷惑,于是在闲暇的时间,查看了jdk文档,并使用少量的代码测试了对几个方法的使用,分享给大家。
1.传输数据
在jdk.doc里有说明:
此类的每个子类都定义了两种获取 和放置 操作:
相对 操作读取或写入一个或多个元素,它从当前位置开始,然后将位置增加所传输的元素数。如果请求的传输超出限制,则相对获取 操作将抛出
BufferUnderflowException
,相对放置 操作将抛出BufferOverflowException
;这两种情况下,都没有数据被传输。绝对 操作采用显式元素索引,该操作不影响位置。如果索引参数超出限制,绝对获取 操作和放置 操作将抛出
IndexOutOfBoundsException
。
当然,通过适当通道的 I/O 操作(通常与当前位置有关)也可以将数据传输到缓冲区或从缓冲区传出数据。
上面的说明初次看会让我很困惑,于是写下了一个测试的方法。
ByteBuffer b = ByteBuffer.allocate(1000);
b.put(new byte[]{0x68}); //将数据塞入缓冲区
b.flip(); //只有在flip之后才可以使用塞入的数据哦。
System.out.println(HexDump.hexDump(b));
输出的结果:68
上面都是没有问题的,接着看下面的。
在上面flip()之后,我再向里面塞入数据,是什么样的结果呢?
b.put(new byte[]{0x61}); //看清楚长度,跟上面一样
b.flip();//再次flip
System.out.println(HexDump.hexDump(b));
输出的结果:61
好的,这样都是没有问题的,无论你向里面插入什么数据(只要长度不超过第一次)都是可以的。
好的,我现在如果向里面塞入两个字节的数据,看一下什么情况。
b.put(new byte[]{0x61,0x62});
b.flip();
System.out.println(HexDump.hexDump(b));
Exception in thread "main" java.nio.BufferOverflowException
at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:165)
at java.nio.ByteBuffer.put(ByteBuffer.java:813)
at test._bytebuffer.TestCompact.main(TestCompact.java:16)
//oh shit!!!
看到错误之后,不要着急,看一下jdc.doc说到的。 这样就属于超过相对数量的传输。
那么这种情况下,我还想用b这个变量,而我就想放两个字节的数据应该怎么办呢?
非常好办啦,在put之前,调用一下b.clear()就可以了。
但是,这样还有一个问题,我不仅要放置两个字节的数据,在输出的时候,我还想将前面的数据也输出出来,这应该怎么办呢?
那我们就是用compact方法,记住在每次put、filp之后调用compact方法,否则就达不到效果了。
ByteBuffer b = ByteBuffer.allocate(1000); b.put(new byte[]{0x68}); b.flip(); b.compact(); System.out.println(HexDump.hexDump(b)); b.put(new byte[]{0x61}); b.flip(); b.compact(); System.out.println(HexDump.hexDump(b)); b.put(new byte[]{0x61,0x61}); b.flip(); System.out.println(HexDump.hexDump(b));
什么情况下会抛出IndexOutOfBoundsException
,这个应该很简单,你的缓冲区的大小只分配了1个字节,你如果插入两个字节就会报出这样的错误。
2.线程安全
在jdk.doc里,明确告诉你Buffer类(ByteBuffer继承自它)不是线程安全的。大白话就是,当多个线程同时调用同一个buffer的时候,数据会出错。这个问题可是之前困扰我很久。现在想想,就想说TMD。
好吧,附上测试代码
package test; import java.nio.ByteBuffer; import cn.hexing.fk.utils.HexDump; public class TestByteBuffer { public static void main(String[] args) { Thread1 t = new Thread1(); Thread1 t2 = new Thread1(); TestMessage1 message = new TestMessage1(); t.message = message; t2.message = message; t.start(); t2.start(); } } class Thread1 extends Thread{ public TestMessage1 message; @Override public void run(){ for(int i = 0 ; i < 10000 ; i++){ ByteBuffer buffer=ByteBuffer.allocateDirect(1000); message.write(buffer); buffer.flip(); String str=HexDump.hexDump(buffer); System.out.println(str); if(str.equals("00 01 00 01 00 01 00 1C CC 1A 30 00 00 0C 68 D3 D3 98 EA 8F 7D 95 DA 46 6F F9 5E B1 DD FC 59 12 51 5B 99 12")){ System.out.println("sdf"); }else{ System.out.println("nonon"); } } } } class TestMessage1 { ByteBuffer apdu = HexDump.toByteBuffer("CC1A3000000C68D3D398EA8F7D95DA466FF95EB1DDFC5912515B9912"); private short version = 0x0001; private short srcAddr = 0x0001; private short dstAddr = 0x0001; public void write(ByteBuffer buffer){ synchronized (this) { buffer.putShort(version); buffer.putShort(srcAddr); buffer.putShort(dstAddr); buffer.putShort((short) apdu.remaining()); while(apdu.hasRemaining() && buffer.hasRemaining()) buffer.put(apdu.get()); apdu.position(0); } } }
上面的代码是没有问题的,就是两个线程拥有一个message,同时调用write方法,由于在write方法里加了synchronized,所以是线程安全的,如果将synchronized去掉的话,输出会出现"nono"哦。
相关推荐
使用nio byteBuffer 实现按行读取文件(大文件) 在window/linux/macOS上均测试通过 对于中文乱码也已处理成功 完整注释,可随需求更改 有问题请邮件:mly610865580@126.com
主要介绍了Android在JNI中使用ByteBuffer的方法,涉及Android中缓冲区的相关使用技巧,需要的朋友可以参考下
仿安卓ByteBuffer 完美组包、拆包
Android
主要解决从流中获取数据,缓存,拆解,可用于TCP粘包问题
【IT十八掌徐培成】Java基础第26天-05.ByteBuffer-mark-pos-limit-cap-flip.zip
易语言汇编版ByteBuffer源码。主要用于各种网络协议的组包 具体用法可以点上面的网址 功能和jAVA的一样。@10371178。Tags:易语言汇编版ByteBuffer源码。
protobuf+long+bytebuffer,利用protobuf.js实现编解码 所需的三个js库
ios-byteBuffer [![CI状态]( Lee / ios-byteBuffer.svg?style = flat)]( Lee / ios-byteBuffer ) 用法 #分配 ByteBuffer *buffer = [ByteBuffer initWithOrder: ByteOrderLittleEndian]; #输入数据 - ( ...
java api之ByteBuffer基础、应用场景、实战讲解 文档中有丰富的例子代码实现
易语言汇编版ByteBuffer源码主要用于各种网络协议的组包 具体用法可以点上面的网址 功能和jAVA的一样
dena-bytebuffer
jdk api-ServerSocketChannel、Selector、ByteBuffer结合实现网络报文间的通讯
NULL 博文链接:https://chinaestone.iteye.com/blog/468138
描述:为了解决java与C结构通信过程中结构体解析问题。 主要功能:能友好的用java处理任何发送的C结构体对象,并且能发送java对象转换成C结构体接收的二进制。 ...4、配置简单,使用方便、易上手。
NULL 博文链接:https://zheng12tian.iteye.com/blog/1094811
或在浏览器中使用: dist/byte-buffer.js dist/byte-buffer.min.js 用法 作为ECMAScript模块: import ByteBuffer from 'byte-buffer' ; const b = new ByteBuffer ( ) ; 在CommonJS环境中: const ByteBuffer...
• Multipurpose ...MINA没有直接使用使用java NIO的ByteBuffer类。它使用一个自制的ByteBuffer来扩展java。如果你使用MINA,你将不需要直接使用NIO buffers,因为仅使用MINA buffers就可以完成大多数buffer操作