Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么ByteBuffer的绝对读取不被认为是线程安全的?_Java_Multithreading_Nio_Bytebuffer - Fatal编程技术网

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

Java 为什么ByteBuffer的绝对读取不被认为是线程安全的?,java,multithreading,nio,bytebuffer,Java,Multithreading,Nio,Bytebuffer,我的用例需要一个直接分配的线程,它被写入一次,然后被多个并发线程读取。所有读取都是绝对的,所以我从不关心缓冲区的状态(位置、限制、标记) Keith Gregory在字节缓冲区上警告说,即使是绝对读取也不被认为是线程安全的: ByteBuffer线程安全在JavaDoc中有介绍;简短的版本是缓冲区不是线程安全的。显然,在没有竞争条件的情况下,您不能使用多线程的相对定位,但即使是绝对定位也不能保证(不管您在查看实现类后会怎么想) (强调矿山) 由于此警告,我在每次读取字节缓冲区之前都会调用。这很容

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

Keith Gregory在字节缓冲区上警告说,即使是绝对读取也不被认为是线程安全的:

ByteBuffer
线程安全在JavaDoc中有介绍;简短的版本是缓冲区不是线程安全的。显然,在没有竞争条件的情况下,您不能使用多线程的相对定位,但即使是绝对定位也不能保证(不管您在查看实现类后会怎么想)

(强调矿山)

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

尽管Keith提出了神奇的免责声明,但我确实看到了OpenJDK从直接字节缓冲区进行绝对读取的方法:

public byte get(int i) {
    return ((unsafe.getByte(ix(checkIndex(i)))));
}
您可以看到它只是委托给,它“从给定的内存地址获取一个值”

我知道可能存在不同的实现,但是这个操作有什么不可能是线程安全的呢?
缓冲区
契约是否只是为了避免部分线程安全类的混淆而拒绝保证绝对读取的线程安全?或者,如果警告是针对并发写入的,那么在创建字节缓冲区后未修改字节缓冲区的情况如何?另外,如果改用a,会有什么变化吗

相关的:


其中一个例子是,缓冲区文档说明对缓冲区的访问应该同步。它并没有说它不能被不同的线程使用。因此,我认为不需要重复的

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


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

Hmm。那里有很多未经证实的观点。例如,“我认为这没有考虑Java内存模型”。实现必须(a)遵守Javadoc中规定的规范,并且(b)在执行此操作时考虑Java内存模型。@EJP Java内存模型备注似乎指的是直接缓冲区,它位于Java堆之外。它们基本上是内存映射的IO操作,文件(或Java堆/堆栈以外的任何东西)上的IO操作不必遵循Java内存模型即使忽略了在没有适当同步的情况下会出现的可见性问题,
get
方法也不是原子的。它访问共享数据数组并执行索引检查,其中包括读取共享状态
限制
。除非某种机制使其线程安全,否则没有任何东西是线程安全的。@PaulBellora-我添加这一行是为了回应在线程之间共享缓冲区的同事。我对你的回答和对他的回答是一样的:是的,在我看来它确实是线程安全的,但是如果我们使用的JVM不是线程安全的,我不想改变很多代码。我相信线程本地拷贝(在那篇文章的下方显示)是最好的方法。我当然不会每次都重复。我更喜欢使用
duplicate
而不是同步来避免争用。不幸的是,你的中间段落更多的是一个评论而不是一个答案-我缺乏证据和有限的想象力是我提出这个问题的原因。@Paul很明显,一次读/写一个字节的实现会导致读/写不完整。@Paul
duplicate
本身不是线程安全的,因此,如果没有适当的同步,您可能无法从不同的线程使用它。