Опции, чтобы сделать поток 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 теперь определяют методы абсолютного массового получения и размещения для передачи непрерывных последовательностей байтов без учета или влияния на позицию буфера.