我有什么选择让ByteBuffer线程安全?众所周知,它不是线程安全的,因为它保护位置,限制和一些(/ all?)方法依赖于这种内部状态。
就我的目的而言,如果多个读线程是安全的就足够了,但对于其他未来的访问者,我想知道我需要知道哪些技术/技巧/陷阱才能使其完全线程安全。
我的想法:
我可以使用哪些其他技巧?我怎么会这样使用DirectBuffer实现“读取时克隆字节” - 它是否可能?可能会将完整的ByteBuffer(ByteBuffer.slice)切成一个解决方案吗?
更新:此question中的含义为“重复(同步)以获取指向相同映射字节的新实例”
答案 0 :(得分:12)
缓冲类可以成为线程安全的...在各个操作已正确同步的意义上,等等。但是,API的设计并未考虑多个线程,因此这可能是浪费时间。
基本问题是Buffer上的各个操作太细粒度而不是同步单元。应用程序无法在get和put操作级别,翻转,位置等方面进行有意义的同步。一般来说,应用程序需要以原子方式执行这些操作的序列,以便有效地同步。
第二个问题是,如果您在精确级别进行同步,则可能会在方法调用上增加大量开销。由于使用Buffer API的目的是有效地进行I / O,这就失去了目的。
如果确实需要同步对共享缓冲区的线程访问,最好使用外部同步;例如像这样的东西:
synchronized (someLock) {
buffer.getByte();
buffer.getLong();
...
}
如果使用给定缓冲区的所有线程都正确同步(例如使用相同的锁对象),则缓冲区不是线程安全的并不重要。线程安全性在缓冲区对象外部进行管理,并且采用更粗粒度的方式。
正如评论所指出的,您还可以使用ByteBuffer.slice()
或buffer.asReadOnlyBuffer()
为您提供另一个缓冲区,并将现有缓冲区作为支持。但是,在任何一种情况下,javadoc都不保证线程安全。实际上,Buffer
{{1}}发表了这个一揽子声明:
多个并发线程使用缓冲区是不安全的。如果要由多个线程使用缓冲区,则应通过适当的同步来控制对缓冲区的访问。
答案 1 :(得分:0)
使用JDK13,您现在可以使用不带byteBuffer.position(int)的ByteBuffer并获得线程安全性。
请参见release notes。
java.nio.ByteBuffer和java.nio中的其他缓冲区类型现在定义了绝对批量get和put方法,以传输连续的字节序列,而不考虑或影响缓冲区位置。