java.nio.ByteBuffer.slice() 线程行为?

java.nio.ByteBuffer.slice() Threading Behaviour?

我明白 java.nio.ByteBuffer 本身不是线程安全的。但是,如果您通过 slice() 获得一个共享的、派生的 ByteBuffer,您是否能够在多个线程中通过不同的切片缓冲区同时访问底层缓冲区的内容?我在 API 规范中找不到任何相关信息...如果此行为未标准化,您知道它在最常见的 VM 中是如何实现的吗?

基本上,如果某些东西没有被记录为线程安全的,就假定它不是;如果某些东西被明确记录为 not 是线程安全的,除非另有说明,否则永远不要假设任何密切相关的东西是线程安全的。


正如您提到的,缓冲区不是线程安全的。 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.

并且 ByteBuffer 的文档扩展了 Buffer,与上述内容并不矛盾。

ByteBuffer#slice() 的文档是这样说的:

Creates a new byte buffer whose content is a shared subsequence [emphasis added] of this buffer's content.

The content of the new buffer will start at this buffer's current position. Changes to this buffer's content will be visible in the new buffer, and vice versa; the two buffers' position, limit, and mark values will be independent. [emphasis added]

The new buffer's position will be zero, its capacity and its limit will be the number of bytes remaining in this buffer, its mark will be undefined, and its byte order will be BIG_ENDIAN. The new buffer will be direct if, and only if, this buffer is direct, and it will be read-only if, and only if, this buffer is read-only.

其他类似的方法,例如 #slice(int,int)#alignedSlice(int),记录了类似的行为。

如您所见,缓冲区实例的内容是共享的。该文档没有提及在这种情况下添加线程安全的任何内容,因此我们可以自信地假设缓冲区的一般线程安全适用——也就是说,没有线程安全。如果写入共享相同内容子序列的任何缓冲区,则所有其他缓冲区都将受到影响。在并发上下文中,如果没有适当的外部同步,这意味着潜在的竞争条件。

我不确定这如何适用于读取和写入不同的(即非重叠的)子序列。我假设适用于数组的任何行为都适用于这种情况。当然,这没有考虑直接缓冲区。

综上所述,这其中有一些微妙之处。如文档所述,每个缓冲区将具有独立的位置、限制和标记值。这样做的结果是每个缓冲区都可以由单独的线程读取。但是,这是buffer和thread的一对一映射(除非你加上外部同步)1。这是因为仅通过读取缓冲区就可以修改位置和标记值(至少,相对读取操作1就是这种情况)和倒带。


1.我相信如果且仅当它们都使用 absolute 读取操作并且不使用时,我相信多个线程可以 read 从同一个缓冲区实例不同步使用标记。也就是说,只要none个线程修改了"meta-state"个buffer。