最近在项目中,频繁使用到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"哦。
相关推荐
2. **直接缓冲区**:对于性能敏感的应用,可以使用`ByteBuffer.allocateDirect(int capacity)`创建直接缓冲区,它直接在物理内存中分配空间,减少了Java对象头的开销,但可能涉及内存复制。 三、ByteBuffer的主要...
- 写入数据:使用ByteBuffer的put方法将转换后的字节序列写入缓冲区,可以按单个字节、短整型、整型、长整型或其他自定义字节数组进行写入。 - 对齐处理:如果需要,可以进行字节对齐,确保数据按照特定的边界对齐...
本主题主要关注的是如何在JavaScript环境中结合protobuf.js库处理`long`类型的数据以及与`ByteBuffer`的配合使用。`long`类型在protobuf中用于表示大整数,而`ByteBuffer`则是protobuf.js提供的一种高效的数据缓冲区...
3. 使用`ByteBuffer.wrap(byte[] array)`:将已有的字节数组包装成ByteBuffer。 接下来,我们探讨ByteBuffer的几个关键属性: - `capacity()`:返回缓冲区的总容量,即可以存储的最大字节数。 - `limit()`:限制了...
下面将详细介绍在Android JNI中使用ByteBuffer的方法及其相关知识点。 首先,了解ByteBuffer的基本概念。ByteBuffer是一个固定大小的列表,用于存储基本数据类型,如字节、短整型、整型、长整型等。它有四个核心...
使用nio byteBuffer 实现按行读取文件(大文件) 在window/linux/macOS上均测试通过 对于中文乱码也已处理成功 完整注释,可随需求更改 有问题请邮件:mly610865580@126.com
比如,从网络接收数据时,我们可能先分配一个足够大的`ByteBuffer`,然后通过网络通道读取数据到缓冲区,使用`flip()`切换到读模式,再从缓冲区读取数据进行处理。 此外,还有其他一些重要的方法,如: - **clear()...
在Mina中,ByteBuffer的使用是至关重要的,因为它提供了高效的数据读写机制。本篇将深入探讨Java NIO(非阻塞I/O)中的ByteBuffer和Mina库自定义的ByteBuffer之间的区别。 Java NIO的ByteBuffer是Java标准库提供的...
使用汇编编写ByteBuffer,可以更精细地控制内存操作,提高代码执行效率,尤其是在处理大量数据时。 4. **接口设计**:易语言的接口设计通常直观且易用,即使是对编程不太熟悉的用户也能快速上手。在ByteBuffer中,...
主要解决从流中获取数据,缓存,拆解,可用于TCP粘包问题
8. **优化的性能**:使用汇编语言实现的ByteBuffer,相比纯易语言版本,通常具有更高的执行效率,尤其是在处理大量数据时。 在使用易语言汇编版ByteBuffer时,开发者需要注意内存管理和性能优化,理解其内部机制,...
ios-byteBuffer [![CI状态]( Lee / ios-byteBuffer.svg?style = flat)]( Lee / ios-byteBuffer ) 用法 #分配 ByteBuffer *buffer = [ByteBuffer initWithOrder: ByteOrderLittleEndian]; #输入数据 - ( ...
java api之ByteBuffer基础、应用场景、实战讲解 文档中有丰富的例子代码实现
本文将详细探讨`dena-bytebuffer`的核心特性、使用方法以及其在实际项目中的应用。 一、`dena-bytebuffer`简介 `dena-bytebuffer`是基于JavaScript的字节缓冲库,它允许开发者以高效的方式处理二进制数据。在...
由于Javolution的`Struct`类可以直接从字节缓冲区读写,我们可以创建一个`ByteBuffer`并使用`Struct.read()`方法: ```java ByteBuffer buffer = ByteBuffer.allocateDirect(MyStruct.SIZE); // SIZE应为结构体的...
jdk api-ServerSocketChannel、Selector、ByteBuffer结合实现网络报文间的通讯
3. **bytebuffer.js**:ByteBuffer是一个二进制缓冲区的实现,类似于Java的ByteBuffer类。在protobuf中,数据是以二进制形式存储和传输的,bytebuffer.js提供了读写二进制数据的能力,这对于处理protobuf序列化的...
在实际的开发中,ByteBuffer的使用通常涉及以下几个知识点: 1. **内存管理**:ByteBuffer允许开发者在堆外分配内存,这可以避免频繁的GC(垃圾回收)操作,提高性能。通过allocateDirect()方法,可以创建直接...