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

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

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

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

Synchronizing or using ReadWrite locks for all methods. Probably the slowest approach (?) Subclassing ByteBuffer and avoid persisting thread-bound state like position etc. And throwing exceptions accordingly for all methods which need to use internal state. This would be the fastes. But are there any traps? (except that I'll have to read the directly mapped memory into heap memory ...)

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

Update: Что подразумевается под этимвопрос с"duplicate (while synchronized) to get a new instance pointing to the same mapped bytes"

 Karussell22 июн. 2012 г., 17:20
спасибо, Питер! Вы используете это через ломтик? или как вы получаете доступ к тем же данным?
 Peter Lawrey24 июн. 2012 г., 11:31
Нет, но у меня есть похожая библиотека с открытым исходным кодом.github.com/peter-lawrey/Java-Chronicle Это основано на записи / строке / отрывке, а не на столбце, но методы те же.
 Karussell23 июн. 2012 г., 18:33
У меня есть удача, а у вас обертка буфера с открытым исходным кодом;)?
 Peter Lawrey22 июн. 2012 г., 15:39
Я предпочитаю использовать модель актера, где любой ByteBuffer обновляется только одним потоком (или только для чтения). Причина, по которой я это делаю, заключается в том, что накладные расходы на синхронизацию обычно перевешивают преимущества наличия нескольких потоков.
 Peter Lawrey22 июн. 2012 г., 17:23
Я не использую срез, вместо этого я использую оболочку, которая скрывает все (даже тот факт, что я использую ByteBuffers, и я могу захотеть переключиться на Unsafe, что немного быстрее) Преимущество использования оболочки заключается в том, что вы можете скрыть все подробности и доступ к вашему & quot; массиву & quot; естественно, вызывая методы. Это особенно полезно, поскольку у меня есть массивы с миллиардами элементов, которые не помещаются в один ByteBuffer.

Ответы на вопрос(1)

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

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

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

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

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

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

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

Buffers are not safe for use by multiple concurrent threads. If a buffer is to be used by more than one thread then access to the buffer should be controlled by appropriate synchronization.

 Karussell22 июн. 2012 г., 14:36
Вы прокомментируете случай буфера только для чтения?
 Karussell23 июн. 2012 г., 18:32
хорошо спасибо! Предполагая, что у меня будет операция только для чтения, и я использую ByteBuffer.slice (чтобы я мог использовать один ByteBuffer на поток) - они все еще являются ловушками :)?
 23 июн. 2012 г., 02:34
@ Karussell - 1), потому что большинство операций обновляют позицию буфера. 2) да, это правда. Но это либо тот, либо методы getXxx (pos)
 Karussell22 июн. 2012 г., 17:20
как это может быть непоследовательным, когда не происходит запись? также резервный массив не всегда существует
 22 июн. 2012 г., 14:50
Я не думаю, что случай только для чтения упрощает вещи, если вы не готовы обрабатывать буфер как простой массив ... извлекать и использовать резервный массив напрямую черезarray(), Даже тогда вам нужна синхронизация, чтобы обеспечить постоянный доступ к памяти.

Ваш ответ на вопрос