簡體   English   中英

原子讀取然后在Java中寫入ByteBuffer的一部分

[英]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。 方法:

  • 您可以創建一個鎖定對象列表,並在每次讀取bytebuffer時僅鎖定一個區域。 像DNA一樣,這應該是最快的解決方案。
  • 或者您甚至可以使用內存映射來解決此問題 ,然后使用FileChannel.lock ,它也會鎖定bytebuffer的一個區域,但是更低級別。 編輯 :這僅保護來自外部程序IMO的訪問
  • 或者您可以使用幾個較小但同步的ByteBuffers +交換信息。 有趣的是 ,線程應該立即看到彼此的變化(這是我得到mmap想法的地方)

我認為將代碼的關鍵部分置於鎖定控制之下應該是干凈的解決方案。 但是,如果您的用例與寫入相比具有大量讀取,則不要直接使用同步。 我建議您使用ReentrantReadWriteLock作為解決方案的一部分。 在修改ByteBuffer的函數中,您可以使用writeLock()。lock()然后使用代碼。 而閱讀時則使用readLock()。lock()。 您可以在上述鏈接上閱讀有關讀寫鎖定的更多信息。 基本上它將允許並發讀取但不允許並發寫入,而寫入正在發生讀取線程等待

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM