Search code examples
javajava-memory-modelnio2

Thread-safety of NIO2 CompletionHandler


Is the following code thread-safe? If so, what guarantees the safe publication of the ByteBuffer instance to the thread executing the 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) {
       //...
    }
});

Solution

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

    The only such authoritative source I know of is javadocs (1, 2, 3).

    Unfortunately, as you can see for yourself, they contain no explicit and clear guarantees of thread-safety.

    It means the code is not thread-safe.


    IMO the guarantees should be given in the javadoc for the method, the method's class, or CompletionHandler — then we can be sure they are implemented for all JVMs and all platforms (and will stay implemented in the future).

    But if you really want, you can "compile" a proof for thread-safety from multiple places in different javadocs:

    • 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

    As a result, we get that every action of the I/O read to ByteBuffer happens-before the first action of CompletionHandler => this means the code is thread-safe.

    IMO "compiled proofs" like the one above are too fragile, and personally I would assume that the code is not thread-safe.