Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在多线程环境中正确使用ByteBuffer?_Java_Multithreading - Fatal编程技术网

Java 如何在多线程环境中正确使用ByteBuffer?

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

在一个名为A类的数据类中,我有以下内容:

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());
关于这一点,有几个问题:

  • 为什么它可以在Linux上工作而不能在Windows上工作(只是时间问题)
  • 我猜问题是由其他人更改限制/位置/标记值引起的,而此CoverInfo对象正在访问ByteBuffer,在这种情况下,duplicate()是首选方法吗
  • 如果使用ByteBuffer的slice(),如果有多个用户修改ByteBuffer,如何保证数据完整性
  • 如何在多线程环境中正确使用ByteBuffer

  • 我想问题在于,有多个线程都试图同时处理缓冲区,尽管它们都没有修改缓冲区中的数据,但它们正在更改缓冲区的状态,特别是读/写位置

    解决方案:

    一次只允许一个线程与缓冲区交互

    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。