下面的代码线程安全吗?如果是,什么保证ByteBuffer实例安全地发布到执行CompletionHandler的线程?
AsynchronousSocketChannel channel = ...
ByteBuffer buf = ByteBuffer.allocate(1024);
channel.read(buf, null, new CompletionHandler<Integer, Void>() {
//"completed" can be executed by a different thread than channel.read()
public void completed(Integer result, Void attachment) {
buf.flip(); //Can buf be safely accessed here? If so, why?
//...
}
public void failed(Throwable exc, Void attachment) {
//...
}
});发布于 2021-08-29 21:55:40
对所有JVM和所有平台有效的权威引用
我所知道的唯一权威来源是javadocs (1 )。
不幸的是,正如您自己看到的,它们没有明确和明确的线程安全保证。
这意味着代码不是线程安全的。
IMO应该在javadoc中为方法、方法类或CompletionHandler提供保证--然后我们可以确定它们是为所有JVM和所有平台实现的(并将在将来继续实现)。
但是,如果您真的需要,可以从不同javadocs中的多个位置“编译”线程安全的证明:
AsynchronousSocketChannel.read(...):处理程序参数是在读取操作完成(或失败)时调用的完成处理程序。java.nio.channels:为了实现资源共享,异步通道被绑定到异步通道组。一个组有一个关联的ExecutorService,向其提交任务以处理I/O事件,并将消耗在组中的通道上执行的异步操作的结果的完成处理程序分派给完成处理程序。ExecutorService:内存一致性效果:在向ExecutorService提交可运行或可调用任务之前,线程中的操作会在该任务采取任何操作之前发生。因此,我们得到ByteBuffer读取的I/O的每一个操作都发生--在CompletionHandler =>的第一个操作之前--这意味着代码是线程安全的。
国际海事组织“汇编的证据”像上面的那样太脆弱了,我个人认为代码不是线程安全的。
发布于 2021-08-26 19:21:48
在javadocs中,我没有看到任何关于ByteBuffer内部状态的显式保证(在read()操作中使用),在read()完成时调用的CompletionHandler中将是可见的。
所以没有百分之百的保证。
但我要说的是,人们普遍认为这是事实。仅仅是因为:
CompletionHandler看到“read()”所做的更改是正常的CompletionHandler可以在不同的线程中异步运行这一事实是read()内部实现的一个细节,因此,确保在这种情况下安全地发布这个东西是read()的关注。但是,如果您不确定/不确定,并且不开发具有纳秒延迟的应用程序--只需添加您自己的额外同步--那么您将100%确信您的程序正确工作。
发布于 2021-08-26 20:19:49
仅仅为了添加对上面的答案,您可能更喜欢通过read(...)方法的attachment参数将ByteBuffer传递给CompletionHandler (就像在五花八门 示例中所做的那样):
AsynchronousSocketChannel channel = ...
ByteBuffer buf = ByteBuffer.allocate(1024);
channel.read(buf, buf, new CompletionHandler<>() {
public void completed(Integer result, ByteBuffer buf) {
buf.flip();
//...
}
public void failed(Throwable exc, ByteBuffer buf) {
//...
}
});因为attachment是read(...)的一个显式参数,所以它必须安全地发布到CompletionHandler的线程中。
不幸的是,我在javadocs中没有看到任何明确的保证,即在完成之后,这个安全发布发生在read(...)上。
https://stackoverflow.com/questions/68936041
复制相似问题