Java 如何在多线程环境中正确使用ByteBuffer?
在一个名为A类的数据类中,我有以下内容:Java 如何在多线程环境中正确使用ByteBuffer?,java,multithreading,Java,Multithreading,在一个名为A类的数据类中,我有以下内容: class A { private byte[] coverInfo = new byte[CoverInfo.SIZE]; private ByteBuffer coverInfoByteBuffer = ByteBuffer.wrap(coverInfo); ... } public void populate(ByteBuffer dataBuf) { dataBuf.rewind(); dataBuf
class A
{
private byte[] coverInfo = new byte[CoverInfo.SIZE];
private ByteBuffer coverInfoByteBuffer = ByteBuffer.wrap(coverInfo);
...
}
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);
}
在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实例,并将数据填充到类A内部的coverInfo对象中,如下所示:
public void createCoverInfo()
{
CoverInfo tempObj = new CoverInfo();
tempObj.populate(coverInfoByteBuffer);
....
}
在CoverInfo类的populate()方法中,我有以下内容:
class A
{
private byte[] coverInfo = new byte[CoverInfo.SIZE];
private ByteBuffer coverInfoByteBuffer = ByteBuffer.wrap(coverInfo);
...
}
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());
关于这一点,有几个问题:
我想问题在于,有多个线程都试图同时处理缓冲区,尽管它们都没有修改缓冲区中的数据,但它们正在更改缓冲区的状态,特别是读/写位置 解决方案: 一次只允许一个线程与缓冲区交互
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);
}
}
或
为每个创建一个新的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);
}
我想问题在于,有多个线程都试图同时处理缓冲区,尽管它们都没有修改缓冲区中的数据,但它们正在更改缓冲区的状态,特别是读/写位置 解决方案: 一次只允许一个线程与缓冲区交互
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);
}
}
或
为每个创建一个新的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);
}
从缓冲区类的
线程安全
多个并发线程使用缓冲区是不安全的。如果一个缓冲区要由多个线程使用,那么应该通过适当的同步来控制对缓冲区的访问
规范上是这么说的。正如您所说,创建多个具有各自独立位置的缓冲区视图等都可以。此外,使用绝对读取(指定位置)也可能有效。根据文档,这些都不能保证工作,并且可能只在某些缓冲区实现上工作。来自buffer类的: 线程安全 多个并发线程使用缓冲区是不安全的。如果一个缓冲区要由多个线程使用,那么应该通过适当的同步来控制对缓冲区的访问
规范上是这么说的。正如您所说,创建多个具有各自独立位置的缓冲区视图等都可以。此外,使用绝对读取(指定位置)也可能有效。根据文档,这些都不能保证工作,并且可能只在某些缓冲区实现上工作。“根据文档,这些都不能保证工作,并且可能只在某些缓冲区实现上工作。”---你是说没有真正的解决方案吗?“根据文档,这些都不能保证工作,并且可能只在某些缓冲区实现上工作。“---你是说没有真正的解决方案吗?我尝试了同步方法,在我的案例中不起作用,因为有其他地方可以访问ByteBuffer。我尝试了同步方法,在我的案例中不起作用,因为还有其他地方可以访问ByteBuffer。