在一个数据类 A类中,我有以下内容:
class A
{
private byte[] coverInfo = new byte[CoverInfo.SIZE];
private ByteBuffer coverInfoByteBuffer = ByteBuffer.wrap(coverInfo);
...
}
在 CoverInfo类中,我的字段很少:
class CoverInfo
{
public static final int SIZE = 48;
private byte[] name = new byte[DataConstants.Cover_NameLength];
private byte[] id = new byte[DataConstants.Cover_IdLength];
private byte[] sex = new byte[DataConstants.Cover_SexLength];
private byte[] age = new byte[DataConstants.Cover_AgeLength];
}
当 A类获取coverInfo数据时,我创建了一个CoverInfo实例,并将数据填充到CoverInfo对象中,如 inside A类:
public void createCoverInfo()
{
CoverInfo tempObj = new CoverInfo();
tempObj.populate(coverInfoByteBuffer);
....
}
在 CoverInfo 类的populate()方法中,我有以下内容:
public void populate(ByteBuffer dataBuf)
{
dataBuf.rewind();
dataBuf.get(name, 0, DataConstants.Cover_NameLength);
dataBuf.get(id, 0, DataConstants.Cover_IdLength);
dataBuf.get(sex, 0, DataConstants.Cover_SexLength);
dataBuf.get(age, 0, DataConstants.Cover_AgeLength);
}
populate()方法将在Windows上抛出异常(始终),但它适用于Linux:
java.nio.BufferUnderflowException
java.nio.HeapByteBuffer.get(HeapByteBuffer.java:151)
com.bowing.uiapp.common.socketdata.message.out.CoverInfo.populate(CoverInfo.java:110)
并且异常行号未固定在一行中。
它正在多线程环境上运行。
如果我使用重复的(只读是好的)ByteBuffer,问题就解决了:
tempObj.populate(coverInfoByteBuffer.duplicate());
关于此的几个问题:
答案 0 :(得分:2)
来自Buffer类的Javadoc:
线程安全
多个并发线程使用缓冲区是不安全的。如果要由多个线程使用缓冲区,则应通过适当的同步来控制对缓冲区的访问。
这就是规范所说的。正如您所说,使用自己的独立位置等创建缓冲区的多个视图可以正常工作。此外,使用绝对读取(您指定位置的位置)也可能有效。这些都不能保证根据文档工作,并且可能仅适用于某些缓冲区实现。
答案 1 :(得分:1)
我猜测问题是你有多个线程同时尝试在缓冲区上工作,尽管它们都没有修改缓冲区中的数据,它们正在改变缓冲区的状态,特别是读/写位置。
解决方案:
一次只允许一个线程与缓冲区进行交互...
public void populate(ByteBuffer dataBuf)
{
synchronized(dataBuf){
dataBuf.rewind();
dataBuf.get(name, 0, DataConstants.Cover_NameLength);
dataBuf.get(id, 0, DataConstants.Cover_IdLength);
dataBuf.get(sex, 0, DataConstants.Cover_SexLength);
dataBuf.get(age, 0, DataConstants.Cover_AgeLength);
}
}
OR
为每个人创建一个新的ByteBuffer。
public void populate(ByteBuffer dataBuf)
{
ByteBuffer myDataBuf = dataBuf.asReadOnlyBuffer();
myDataBuf.get(name, 0, DataConstants.Cover_NameLength);
myDataBuf.get(id, 0, DataConstants.Cover_IdLength);
myDataBuf.get(sex, 0, DataConstants.Cover_SexLength);
myDataBuf.get(age, 0, DataConstants.Cover_AgeLength);
}