为什么ByteBuffer的绝对读取不被认为是线程安全的?

时间:2014-11-04 06:05:15

标签: java multithreading nio bytebuffer

我的用例需要一个直接分配的ByteBuffer,它被写入一次,然后由许多并发线程读取。所有读取都是绝对的,所以我从不关心缓冲区的状态(位置,限制,标记)。

Keith Gregory在字节缓冲区上的

This article警告说,即使绝对读取也不被认为是线程安全的:

  Buffer JavaDoc涵盖了

ByteBuffer线程安全性;简短的版本是缓冲区不是线程安全的。显然,你不能在没有竞争条件的情况下使用来自多个线程的相对定位,但是即使绝对定位也不能保证(无论你在查看实现类之后想到什么)

(强调我的)

由于这个警告,我通过调用duplicate在字节缓冲区的每次读取之前。这很容易,但每次读取时额外的对象分配让我很好奇为什么它实际上是必要的。

尽管Keith的精灵免责声明,我确实看过OpenJDK的implementation来自直接字节缓冲区的绝对读取:

public byte get(int i) {
    return ((unsafe.getByte(ix(checkIndex(i)))));
}

您可以看到它只是委托给Unsafe.getByte(long),"从给定的内存地址中提取值"。

据我所知,可能存在不同的实现,但是对于此操作而言,有什么理由不是线程安全的? Buffer契约是否只是拒绝保证绝对读取的线程安全性,以避免部分线程安全类的混淆?或者如果警告对于并发写入是合理的,那么我的情况如何,在创建后字节缓冲区未被修改?此外,使用MappedByteBuffer时会有什么变化吗?

相关:

1 个答案:

答案 0 :(得分:-1)

对于一个Buffer文档说明应该同步对缓冲区的访问。它没有说它不能被不同的线程使用。所以我认为不需要duplicate

你无法想到某种方法或其他方法的合理的非线程安全实现更多是你的想象力的限制,而不是证明没有必要谨慎。特别是考虑到您没有查看Oracle Java代码,当时Oracle声称实现不是线程安全的。

我建议:访问缓冲区时要做一些合理的同步。即使永远不会有非线程安全实现,也不会花费太多。