简体   繁体   English

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

[英]how to use ByteBuffer properly in multiple thread environment?

In one data class, class A , I have the following: 在一个数据类A类中 ,我具有以下内容:

class A
{
    private byte[] coverInfo = new byte[CoverInfo.SIZE];

    private ByteBuffer coverInfoByteBuffer = ByteBuffer.wrap(coverInfo);
    ...
}

In a CoverInfo class , I have few fields: 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];

}

When class A get the coverInfo data, I create an instance of CoverInfo and and populate data into the CoverInfo object like this inside the Class A: A类获得coverInfo数据,我创建CoverInfo和实例和数据填充到CoverInfo对象这样的A类里面

public void createCoverInfo()
{
    CoverInfo tempObj = new CoverInfo();
    tempObj.populate(coverInfoByteBuffer);
    ....
}

In the populate() method of the CoverInfo class, I have the following: 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);
}

The populate() method will throw exception on Windows ( always ) but it works on Linux: 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)

And the Exception line number is not fixed in one line. 并且例外行号不是固定在一行中。

It is running on multiple threads environment . 它运行在多线程环境中

If I use a duplicated (read-only is fine) ByteBuffer, the issue resolved: 如果我使用重复的(只读就可以)ByteBuffer,问题已解决:

tempObj.populate(coverInfoByteBuffer.duplicate());

Few questions about this: 关于此的几个问题:

  1. why it works on Linux but not on Windows (just a timing issue)? 为什么它可以在Linux上运行而不能在Windows上运行(只是时间问题)?
  2. I guess the issue is caused by the limit/position/mark values are changed by others while this CoverInfo object is accessing the ByteBuffer, the duplicate() is the preferred way for this situation? 我猜这个问题是由这个CoverInfo对象访问ByteBuffer时,其他人更改了限制/位置/标记值引起的,对于这种情况,首选的方法是plicate()?
  3. If the ByteBuffer's slice() is used, how to guarantee data integrity if more than one user to modify the ByteBuffer? 如果使用ByteBuffer的slice(),如果有多个用户修改ByteBuffer,如何保证数据完整性?
  4. how to use ByteBuffer properly in multiple thread environment? 如何在多线程环境中正确使用ByteBuffer?

From the Javadoc of the Buffer class: 从Buffer类的Javadoc中:

Thread safety 线程安全

Buffers are not safe for use by multiple concurrent threads. 缓冲区不能安全地供多个并发线程使用。 If a buffer is to be used by more than one thread then access to the buffer should be controlled by appropriate synchronization. 如果一个缓冲区将由多个线程使用,则应通过适当的同步来控制对该缓冲区的访问。

That's what the spec says. 这就是规范所说的。 As you said, creating multiple views of the buffer with their own independent positions, etc. can work. 如您所说,可以创建具有各自独立位置的缓冲区的多个视图,等等。 Also, using absolute reads (where you specify a position) might also work. 同样,使用绝对读取(您在其中指定位置)也可能有效。 None of these are guaranteed to work according to the documentation and might work only on some buffer implementations. 根据文档,不能保证所有这些都可以起作用,并且可能仅在某些缓冲区实现上起作用。

I'm guess the problem is that you have multiple threads all trying to work on the buffer at the same time, despite none of them modifying the data in the buffer they are changing the state of the buffer specifically the read/write position. 我想问题是,您有多个线程都试图同时在缓冲区上工作,尽管它们都没有修改缓冲区中的数据,但它们正在更改缓冲区的状态,特别是读/写位置。

Solutions: 解决方案:

Only allow one thread at a time to interact with the buffer... 一次只允许一个线程与缓冲区交互...

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 要么

Create a new ByteBuffer for each. 为每个创建一个新的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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM