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



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

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


如前所述,缓冲区不是线程安全的。这由Buffer记录:

缓冲区对于多个并发线程使用不安全。如果缓冲区要由多个线程使用,则应通过适当的同步来控制对该缓冲区的访问。

而延伸BufferByteBuffer文献与上述内容并不矛盾。

以下是ByteBuffer#slice()的文档内容:

创建一个新的字节缓冲区,其内容是此缓冲区内容的共享子序列[强调添加]。

新缓冲区的内容将从此缓冲区的当前位置开始。对此缓冲区内容的更改将在新缓冲区中可见,反之亦然;两个缓冲区的位置、限制和标记值将是独立的。[着重号后加]

新缓冲区的位置将为零,其容量和限制将是此缓冲区中剩余的字节数,其标记将未定义,其字节顺序将为BIG_ENDIAN。当且仅当此缓冲区是直接缓冲区时,新缓冲区将是直接的,并且当且仅当此缓冲区是只读时,新缓冲区将是只读的。

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

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

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

话虽如此,这有一些微妙之处。如前所述,每个缓冲区将具有独立的位置、限制值和标记值。这样做的结果是每个缓冲区都可以由单独的线程读取。但是,这是缓冲区和线程之间的一对一映射(除非添加外部同步(1。这是因为只需读取缓冲区(至少相对读取操作1就是这种情况(并倒带即可修改位置和标记值。


1. 我相信多个线程可以在不同步的情况下同一个缓冲区实例读取,当且仅当它们都使用绝对读取操作并且不使用标记时。换句话说,只要没有线程修改缓冲区的"元状态"。

最新更新