java .nio.ByteBuffer.slice () Поведение потоков? - PullRequest
2 голосов
/ 29 января 2020

Я понимаю, что java .nio.ByteBuffer сам по себе не является потокобезопасным. Однако, если вы получите общий, производный ByteBuffer через slice (), сможете ли вы одновременно получать доступ к содержимому основного буфера в нескольких потоках через разные буферы slice'd? Я не могу найти ничего об этом в API spe c ... Если это поведение не стандартизировано, знаете ли вы, как оно реализовано в наиболее распространенных виртуальных машинах?

1 Ответ

4 голосов
/ 29 января 2020

По сути, если что-то не документировано как поточно-ориентированное, предположим, что это не так; если что-то явно задокументировано как не поточно-ориентированный, никогда не предполагайте, что что-либо тесно связанное является поточно-ориентированным, если не указано иное.


Как вы упоминаете, буферы не поточнобезопасны , Это задокументировано Buffer:

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

И документация ByteBuffer, которая расширяет Buffer, не противоречит вышесказанному.

Вот что говорит документация ByteBuffer#slice():

Создает новый байтовый буфер, содержимое которого представляет собой разделяемую подпоследовательность [выделение добавлено] содержимого этого буфера.

Содержимое нового буфера начнется с текущей позиции этого буфера. Изменения содержимого этого буфера будут видны в новом буфере, и наоборот; значения положения, лимита и метки двух буферов будут независимыми. [выделение добавлено]

Позиция нового буфера будет равна нулю, его емкость и предел будут равны количеству байтов, оставшихся в этом буфер, его метка будет неопределенной, а порядок байтов будет BIG_ENDIAN. Новый буфер будет прямым, если и только если этот буфер является прямым, и он будет доступен только для чтения, если и только если этот буфер доступен только для чтения.

Другие похожие методы, такие как #slice(int,int) и #alignedSlice(int), документируют похожее поведение.

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

Я не уверен, как это относится к чтению и записи в различные (то есть непересекающиеся) подпоследовательности. Я предполагаю, что любое поведение относится к массивам в этом случае. Конечно, это не учитывает прямые буферы.

При всем этом есть некоторые тонкости в этом. Как задокументировано, каждый буфер будет иметь независимые значения позиции, предела и метки. Следствием этого является то, что каждый буфер может считываться отдельным потоком. Однако это взаимно-однозначное сопоставление между буфером и потоком (если вы не добавите внешнюю синхронизацию) 1 . Это связано с тем, что значения позиции и метки можно изменить, просто прочитав буфер (по крайней мере, так обстоит дело с относительно операций чтения 1 ) и перемотав.


1. Я полагаю, что несколько потоков могут читать из одного и того же экземпляра буфера без синхронизации тогда и только тогда, когда все они используют операции чтения absolute и не используют метки. Другими словами, пока ни один из потоков не изменяет «метасостояние» буфера.

...