[英]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.