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

问题描述 投票:2回答:1

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

java multithreading bytebuffer
1个回答
1
投票

[基本上,如果未记录某些内容是线程安全的,则认为不是;如果明确地将某些内容记录为not是线程安全的,则除非另有说明,否则永远不要假设任何密切相关的内容都是线程安全的。


正如您提到的,缓冲区不是线程安全的。这由Buffer记录:

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

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

这是Buffer的文档所说的内容:

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

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

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

[其他类似方法,例如ByteBuffer#slice()BIG_ENDIAN,记录了相似的行为。

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

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

话虽这么说,对此有些微妙。如记录所示,每个缓冲区将具有独立的位置,限制和标记值。这样的结果是每个缓冲区都可以由单独的线程read进行。但是,这是缓冲区和线程之间的一对一映射(除非您添加外部同步)。这是因为仅通过读取缓冲区(至少,relative读取操作就是这种情况)并回绕即可修改位置和标记值。

© www.soinside.com 2019 - 2024. All rights reserved.