我在java中有ByteBuffer,想要读取,然后有条件地修改该字节,例如使用如下方法:
public void updateByte(int index) {
byte b = this.buffer.getByte(index);
if (b == someByteValue) {
this.buffer.setByte(index, someNewByte);
}
}
如何确保读取然后修改字节是原子地发生的?
我不想同步整个ByteBuffer或updateByte
方法,因为我希望多个线程能够同时读取/写入缓冲区的不同字节(即updateByte
可以只要index
不同,就可以被许多线程同时调用。
我使用的ByteBuffer没有字节[]支持,所以在上面的示例中为bb.hasArray() == false
。
答案 0 :(得分:5)
如何为ByteBuffer的部分提供一组显式锁定对象(部分可能非常小,例如一个字,或者相当大,例如四个四分之一缓冲区)?
当一个线程要检查并修改一个字节时,它必须首先获取相应部分的锁,执行其工作,然后释放锁。
这将允许多个线程访问数据的不同部分,而不需要全局同步。
答案 1 :(得分:3)
我不相信你可以在Java中原子地访问字节。您可以做的最好是修改int
值。这将允许您模拟修改单个字节。
您可以使用Unsafe(在许多JVM上)进行比较并交换数组()(堆ByteBuffer)或地址()(直接ByteBuffer)
答案 2 :(得分:3)
简短回答:如果不诉诸JNI,你就不能。
更长的答案:ByteBuffer API中没有原子更新。此外,没有严格定义ByteBuffer与内存的交互。在Sun实现中,用于访问原始内存的方法不会尝试刷新缓存,因此您可能会在多核处理器上看到过时的结果。
另外,请注意Buffer
(及其子类,如ByteBuffer)被明确记录为不是线程安全的。如果有多个线程访问同一个缓冲区,则(1)依赖实现行为进行绝对访问,或(2)编写损坏的代码以进行相对访问。
答案 3 :(得分:1)
就个人而言,我会锁定一个互斥锁,直到找出将数据写入然后释放互斥锁的偏移量。这样你可以锁定很短的时间
答案 4 :(得分:1)
关于此list的并发DirectByteBuffer的长篇主题:
答案应为“是”。
另一个大例子是NIO.2。写/读操作提交字节缓冲区,调用CompletionHandler时可以。
因为在NIO.2情况下,只应用了DirectByteBuffer。对于“克隆”到DirectByteBuffer的非Direct-ByteBuffer,它不是真正的低级操作的参数。
答案 5 :(得分:0)
应该可以锁定ByteBuffer。方法:
答案 6 :(得分:0)
我认为将代码的关键部分置于锁定控制之下应该是干净的解决方案。但是,如果您的用例与写入相比具有大量读取,则不要直接使用同步。我建议您使用ReentrantReadWriteLock作为解决方案的一部分。在修改ByteBuffer的函数中,您可以使用writeLock()。lock()然后使用代码。而阅读时则使用readLock()。lock()。您可以在上述链接上阅读有关读写锁定的更多信息。基本上它将允许并发读取而不是并发写入,而写入正在发生读取线程等待