Опции, чтобы сделать поток Java ByteBuffer безопасным

Какие варианты я должен сделать поток ByteBuffer безопасным? Известно, что он не является потокобезопасным, так как он защищает позиции, лимиты и некоторые (/ все?) Методы зависят от этого внутреннего состояния.

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

Что я имею в виду:

  • Синхронизация или использование блокировок ReadWrite для всех методов. Вероятно, самый медленный подход (?)
  • Создайте подклассы ByteBuffer и избегайте сохранения состояния, связанного с потоком, например, положения и т. Д. И, соответственно, генерирования исключений для всех методов, которые должны использовать внутреннее состояние. Это были бы посты. Но есть ли ловушки? (за исключением того, что мне придется читать непосредственно отображенную память в кучную память...)

Какие еще хитрости я могу использовать? Как, например, реализовать "клонирование байтов при чтении" в DirectBuffer - возможно ли это вообще? Возможно ли нарезка полного ByteBuffer (ByteBuffer.slice) в одном решении?

Обновление: что подразумевается в этом вопросе под "дублированием (при синхронизации), чтобы получить новый экземпляр, указывающий на те же отображенные байты"

1 ответ

Класс Buffer можно сделать поточно-ориентированным... в том смысле, что отдельные операции были должным образом синхронизированы и так далее. Однако API не предназначен для работы с несколькими потоками, так что это, вероятно, пустая трата времени.

Основная проблема заключается в том, что отдельные операции в буфере слишком детализированы, чтобы быть единицей синхронизации. Приложение не может полноценно синхронизироваться на уровне операций get и put, или flip, position и так далее. Вообще говоря, приложение должно выполнять последовательности этих операций атомарно для эффективной синхронизации.

Вторая проблема заключается в том, что если вы синхронизируете на хорошем уровне, это может привести к значительным накладным расходам на вызовы методов. Поскольку смысл использования API-интерфейсов Buffer заключается в эффективном выполнении операций ввода-вывода, это противоречит цели.


Если вам нужно синхронизировать доступ потоков к общему буферу, лучше использовать внешнюю синхронизацию; например что-то вроде этого:

    synchronized (someLock) {
        buffer.getByte();
        buffer.getLong();
        ...
    }

При условии, что все потоки, которые используют данный буфер, синхронизируются должным образом (например, с использованием одного и того же объекта блокировки), не имеет значения, что буфер не является потокобезопасным. Безопасность потока управляется внешне по отношению к объекту буфера и более грубо.


Как отмечают комментарии, вы также можете использовать ByteBuffer.slice() или же buffer.asReadOnlyBuffer() чтобы дать вам еще один буфер с существующим в качестве поддержки. Тем не менее, Javadocs не гарантируют безопасность потоков в любом случае. Действительно, Javadocs для Buffer сделать это общее заявление:

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

С JDK13 теперь вы можете использовать ByteBuffer без byteBuffer.position(int) и получить потокобезопасность.

См. Примечания к выпуску.

java.nio.ByteBuffer и другие типы буферов в java.nio теперь определяют методы абсолютного массового получения и размещения для передачи непрерывных последовательностей байтов без учета или влияния на позицию буфера.

Другие вопросы по тегам