Атомное чтение, а затем запись части ByteBuffer в Java - PullRequest
4 голосов
/ 17 февраля 2012

У меня есть ByteBuffer в Java, и я хочу прочитать, а затем условно изменить этот байт, например, с помощью метода, подобного:

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 в примере выше.

Ответы [ 7 ]

5 голосов
/ 17 февраля 2012

Как насчет предоставления набора явных объектов блокировки для частей ByteBuffer (части могут быть очень маленькими, например, одним словом, или довольно большими, например, четырьмя четвертными буферами)?

Когда поток хочет проверить и изменить байт, он должен сначала получить блокировку для соответствующей части, выполнить свою работу, а затем снять блокировку.

Это позволило бы доступ к различным частям данных несколькими потоками, не требуя глобальной синхронизации.

3 голосов
/ 17 февраля 2012

Краткий ответ: нельзя, не прибегая к JNI.

Более длинный ответ: в ByteBuffer API нет атомарных обновлений. Более того, взаимодействие ByteBuffer с памятью не является строго определенным. А в реализации Sun методы, используемые для доступа к необработанной памяти, не пытаются очистить кэш, поэтому вы можете увидеть устаревшие результаты на многоядерном процессоре.

Кроме того, имейте в виду, что Buffer (и его подклассы, такие как ByteBuffer) явно задокументированы как не поточно-ориентированные. Если у вас есть несколько потоков, обращающихся к одному и тому же буферу, вы (1) полагаетесь на поведение реализации для абсолютного доступа или (2) пишете неработающий код для относительного доступа.

3 голосов
/ 17 февраля 2012

Я не верю, что вы можете получить доступ к байту атомарно в Java. Лучшее, что вы можете сделать, это изменить значения int. Это позволит вам смоделировать изменение одного байта.

Вы можете использовать Unsafe (на многих JVM) для сравнения и замены массива () (heap ByteBuffer) или address () (прямой ByteBuffer)

1 голос
/ 10 июня 2013

Длинная длинная ветка о параллельном DirectByteBuffer в этом списке :

Ответ должен быть "ДА".

Другой БОЛЬШОЙ пример - NIO.2. Операция записи / чтения отправляет байтовые буферы, все нормально, когда вызывается CompletionHandler.

Потому что в случае NIO.2 применяется только DirectByteBuffer. Для Non-Direct-ByteBuffer, который «клонирован» в DirectByteBuffer, это НЕ параметры реальных операций более низкого уровня.

1 голос
/ 05 марта 2012

Лично я бы заблокировал мьютекс, пока не выясню смещение для записи данных, а затем освободю мьютекс.Таким образом, вы блокируете на очень короткое время

0 голосов
/ 12 июня 2013

Я думаю, что помещение критической секции кода под контроль блокировки должно быть чистым решением.Однако не используйте синхронизацию напрямую, если ваш сценарий использования имеет большое количество операций чтения по сравнению с операциями записи.Я бы посоветовал вам использовать ReentrantReadWriteLock как часть вашего решения.В функции, где вы модифицируете ByteBuffer, вы берете writeLock (). Lock (), а затем ваш код.И во время чтения используйте readLock (). Lock ().Вы можете прочитать больше о блокировке чтения-записи по упомянутой ссылке.По сути, это позволит выполнять параллельные чтения, но не одновременные записи, и пока запись происходит, потоки чтения ждут

0 голосов
/ 04 мая 2012

Должна быть возможность заблокировать ByteBuffer.Методы:

  • Вы можете создать список объектов блокировки и заблокировать только одну область на чтение байтового буфера.Как предполагает ДНК, это должно быть самое быстрое решение.
  • , или вы могли бы даже использовать отображение памяти для решения этой проблемы , а затем использовать FileChannel.lock , что такжезаблокировать область байтового буфера, но на более низком уровне. Редактировать : это защищает доступ только от внешних программ IMO
  • Или вы можете использовать несколько меньших, но синхронизированных ByteBuffers + обмен информацией. интересно отметить , что потоки должны немедленно видеть изменения друг от друга (вот где я получил идею mmap)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...