По сути, если что-то не документировано как поточно-ориентированное, предположим, что это не так; если что-то явно задокументировано как не поточно-ориентированный, никогда не предполагайте, что что-либо тесно связанное является поточно-ориентированным, если не указано иное.
Как вы упоминаете, буферы не поточнобезопасны , Это задокументировано Buffer
:
Буферы небезопасны для использования несколькими параллельными потоками. Если буфер должен использоваться более чем одним потоком, то доступ к буферу должен контролироваться соответствующей синхронизацией.
И документация ByteBuffer
, которая расширяет Buffer
, не противоречит вышесказанному.
Вот что говорит документация ByteBuffer#slice()
:
Создает новый байтовый буфер, содержимое которого представляет собой разделяемую подпоследовательность [выделение добавлено] содержимого этого буфера.
Содержимое нового буфера начнется с текущей позиции этого буфера. Изменения содержимого этого буфера будут видны в новом буфере, и наоборот; значения положения, лимита и метки двух буферов будут независимыми. [выделение добавлено]
Позиция нового буфера будет равна нулю, его емкость и предел будут равны количеству байтов, оставшихся в этом буфер, его метка будет неопределенной, а порядок байтов будет BIG_ENDIAN
. Новый буфер будет прямым, если и только если этот буфер является прямым, и он будет доступен только для чтения, если и только если этот буфер доступен только для чтения.
Другие похожие методы, такие как #slice(int,int)
и #alignedSlice(int)
, документируют похожее поведение.
Как видите, содержимое экземпляров буфера является общим. В документации ничего не говорится о добавлении безопасности потоков в этой ситуации, поэтому мы можем с уверенностью предположить, что применяется общая безопасность потоков буферов, то есть безопасности потоков не существует. Если какой-либо буфер, совместно использующий ту же подпоследовательность содержимого, записывается, все другие буферы будут затронуты. В параллельном контексте, без надлежащей внешней синхронизации это означает потенциальные условия гонки.
Я не уверен, как это относится к чтению и записи в различные (то есть непересекающиеся) подпоследовательности. Я предполагаю, что любое поведение относится к массивам в этом случае. Конечно, это не учитывает прямые буферы.
При всем этом есть некоторые тонкости в этом. Как задокументировано, каждый буфер будет иметь независимые значения позиции, предела и метки. Следствием этого является то, что каждый буфер может считываться отдельным потоком. Однако это взаимно-однозначное сопоставление между буфером и потоком (если вы не добавите внешнюю синхронизацию) 1 . Это связано с тем, что значения позиции и метки можно изменить, просто прочитав буфер (по крайней мере, так обстоит дело с относительно операций чтения 1 ) и перемотав.
1. Я полагаю, что несколько потоков могут читать из одного и того же экземпляра буфера без синхронизации тогда и только тогда, когда все они используют операции чтения absolute и не используют метки. Другими словами, пока ни один из потоков не изменяет «метасостояние» буфера.