我的用例需要一个直接分配ByteBuffer,写入一次,然后由许多并发线程读取 . 所有读数都是绝对的,所以我的状态(位置,限制,标记) .
关于字节缓冲区的This article由Keith Gregory警告说,即使绝对读取也不被认为是线程安全的:
ByteBuffer线程安全性包含在Buffer JavaDoc中;简短的版本是缓冲区不是线程安全的 . 显然,在没有竞争条件的情况下,您不能使用来自多个线程的相对定位,但即使绝对定位也无法保证(无论您在查看实现类后如何看待) .
(强调我的)
由于这个警告,我在字节缓冲区的每次读取之前调用duplicate . 这很容易,但每次读取时额外的对象分配让我很好奇为什么它实际上是必要的 .
尽管Keith 's wizardly disclaimer, I did look at OpenJDK' s implementation是来自直接字节缓冲区的绝对读取:
public byte get(int i) {
return ((unsafe.getByte(ix(checkIndex(i)))));
}
你可以看到它只是委托给Unsafe.getByte(long),"fetches a value from a given memory address" .
我知道可能存在不同的实现,但对于此操作而言,合理地不能保证线程安全吗? Buffer
Contract 是否只是拒绝保证绝对读取的线程安全性,以避免部分线程安全类的混淆?或者如果警告对于并发写入是合理的,那么我的情况如何,在创建后字节缓冲区未被修改?而且,使用MappedByteBuffer时会有什么变化吗?
有关:
1 回答
其中一个Buffer文档指出应该同步对缓冲区的访问 . 它没有说它不能被不同的线程使用 . 所以我认为不需要
duplicate
.你不能想到某种方法或其他方法的合理的非线程安全实现更多是你的想象力的限制,而不是证明没有必要谨慎 . 特别是考虑到你没有查看Oracle Java代码,当时Oracle声称实现不是线程安全的 .
我建议:访问缓冲区时要做一些合理的同步 . 即使永远不会有非线程安全实现,也不会花费太多 .