2012-02-17 45 views
4

我在java中有一个ByteBuffer,并且想要读取,然后有条件地修改该字节,例如,用类似的方法:原子读取然后写入Java中的一部分ByteBuffer

public void updateByte(int index) { 
    byte b = this.buffer.getByte(index); 

    if (b == someByteValue) { 
     this.buffer.setByte(index, someNewByte); 
    } 
} 

如何确保读取和然后修改字节发生原子?

我不想整个字节缓冲区或updateByte方法同步,因为我想多线程,以便能够同时读/写缓冲器的不同字节(即updateByte可以同时由多个线程作为所谓只要index不同)。

我使用的ByteBuffer不支持byte [],所以在上面的例子中使用bb.hasArray() == false

回答

3

简短的回答一个比较和交换:你不能,而不诉诸到JNI。

较长的答案:ByteBuffer API中没有原子更新。此外,ByteBuffer与内存的交互不是严格定义的。在Sun实施中,用于访问原始内存的方法不会尝试刷新缓存,因此您可能会在多核处理器上看到陈旧的结果。

此外,请注意,Buffer(及其子类(如ByteBuffer))明确记录为非线程安全。如果你有多个线程访问同一个缓冲区,你(1)依靠绝对访问的实现行为,或者(2)为相对访问写入破坏的代码。

+0

,我将使用一个MappedByteBuffer从FileChannel(这是线程)创建这是真的,所以我假定映射的缓冲器会也是安全的。 – 2012-02-17 13:05:10

+1

@戴夫 - 一个MappedByteBuffer没有连接到FileChannel用于创建它。后者仅用于为* mmap *系统调用提供参数。 – kdgregory 2012-02-17 13:46:09

+0

您可以创建是否和使用您自己的java.util.concurrent.lock.ReadWriteLock的实例。让所有读取/写入特定“原子字节”或“原子字节区域”的代码首先为该字节/区域取出相应的锁。 :) – 2013-07-17 14:54:39

3

我不相信你可以在Java中以原子方式访问字节。你可以做的最好的是修改int值。这将允许您模拟修改单个字节。

您可以使用不安全的(在许多JVM)做的阵列()(堆的ByteBuffer)或地址()(直接ByteBuffer)

5

如何为ByteBuffer的部分提供一组显式锁定对象(部分可能非常小,例如一个字或非常大,例如四个四分之一缓冲区)?

当一个线程想要检查和修改一个字节时,它必须首先获取适当部分的锁,执行它的工作,然后释放锁。

这将允许通过多个线程访问数据的不同部分,而不需要全局同步。

1

就我个人而言,我会锁定一个互斥锁,直到找出将数据写入数据的偏移量,然后释放该互斥量。这样你锁定很短的时间

0

应该可以锁定ByteBuffer。方法:

  • 你可以创建锁定对象的列表,并锁定每字节缓冲区的读取只有一个区域。就像DNA所暗示的那样,这应该是最快的解决方案。
  • 或者你甚至可以使用memory mapping to solve this,然后使用FileChannel.lock这也将锁定字节缓冲区的一个区域,但在更低的水平。 编辑:这只能保护来自外部程序的访问IMO
  • 或者您可以使用几个较小但同步的ByteBuffers +交换信息。这是interesting to note的线程应该马上看到变化相互(这是我得到的MMAP想法)
1

长很长的螺纹有关并发DirectByteBuffer在这个list

答案应该是“是”。

另一大的例子是NIO.2。写入/读取操作提交字节缓冲区,当CompletionHandler被调用时可以。

Ofcause,在NIO.2情况下,仅施加DirectByteBuffer。对于“克隆”到DirectByteBuffer的非直接字节缓冲区,它不是真正的低级操作的参数。

0

我认为把代码的关键部分锁定控制下应该是干净的解决方案。但是,如果您的用例与写入相比具有较高的读取次数,则不要直接使用同步。我建议你使用ReentrantReadWriteLock作为你的解决方案的一部分。在你修改ByteBuffer的函数中,你需要writeLock()。lock()然后你的代码。阅读时使用readLock()。lock()。您可以阅读关于提到的链接上的读写锁定的更多信息。基本上,它会允许并发读但不并发写入,并同时写入正在发生读取线程等待

相关问题