NIO2 CompletionHandler 的线程安全

Thread-safety of NIO2 CompletionHandler

下面的代码是线程安全的吗?如果是这样,什么保证 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) {
       //...
    }
});

我在 javadocs 中没有看到任何关于 ByteBuffer 的内部状态的明确保证,用于 read() 操作,在 CompletionHandler 中可见 CompletionHandler 11=] 完成。

所以没有100%的保证。

但我想说,这是常识,希望这是真的。 仅仅因为:

  1. 期望 CompletionHandler 看到 'read()'
  2. 所做的更改是正常的
  3. CompletionHandler 可以在不同线程中异步 运行 这一事实 — 是 read() 内部实现的细节。因此,read() 需要确保在这种情况下安全发布该内容。

但如果您是 unsure/unconvinced,并且您不开发具有纳秒级延迟的应用程序 — 只需添加您自己的额外同步 — 您将 100% 确定您的程序正常工作。

只需添加 , you might prefer to pass ByteBuffer to CompletionHandler via attachment argument of read(...) method (as it's done in various examples):

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) {
       //...
    }
});

由于 attachmentread(...) 的显式参数,它必须安全地发布到 CompletionHandler 的线程。
不幸的是,我没有在 javadocs 中看到任何明确保证此安全发布发生 after read(...) 完成。

an authoritative reference that is valid for all JVMs and all platforms

我所知道的唯一权威来源是 javadocs (1, 2, 3)。

不幸的是,正如您自己所见,它们没有明确明确的线程安全保证。

这意味着代码不是线程安全的。


IMO 应该在 the method, the method's classCompletionHandler 的 javadoc 中给出保证——这样我们就可以确定它们已在所有 JVM 和所有平台上实现(并将在未来继续实现) ).

但如果您确实需要,您可以从不同 javadoc 的多个位置“编译”线程安全证明:

  • AsynchronousSocketChannel.read(...):

    The handler parameter is a completion handler that is invoked when the read operation completes (or fails).

  • java.nio.channels:

    Asynchronous channels are bound to an asynchronous channel group for the purpose of resource sharing. A group has an associated ExecutorService to which tasks are submitted to handle I/O events and dispatch to completion handlers that consume the result of asynchronous operations performed on channels in the group.

  • ExecutorService:

    Memory consistency effects: Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task

因此,我们得到 I/O 的每个动作读取到 ByteBuffer 发生在 CompletionHandler 的第一个动作之前=> 这意味着代码是线程安全的。

像上面那样的 IMO“编译证明”太脆弱了,我个人认为代码不是线程安全的。