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