Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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) {
       //...
    }
});
like image 914
Malt Avatar asked Aug 26 '21 09:08

Malt


3 Answers

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.

like image 110
user16782457 Avatar answered Sep 20 '22 17:09

user16782457


I don't see in javadocs any explicit guarantees about inner state of a ByteBuffer, used in a read() operation, to be visible inside CompletionHandler called when the read() completes.

So there is no 100% guarantee.

But I would say that it is common sense to expect that to be true. Simply because:

  1. it's normal to expect CompletionHandler to see the changes made by the 'read()'
  2. the fact that CompletionHandler can be run asynchronously in a different thread — is a detail of read()'s internal implementation. As a result, it's a read()'s concern to make sure that thing are safely published in such cases.

But if you are unsure/unconvinced, and you don't develop applications with nanosecond delays — just add your own additional synchronization — and you will be 100% sure that your program works correctly.

like image 26
user16762087 Avatar answered Sep 18 '22 17:09

user16762087


Just to add to the answer above, 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) {
       //...
    }
});

Since attachment is an explicit argument for read(...), it must be safely published to CompletionHandler's thread.
Unfortunately, I don't see in javadocs any explicit guarantees that this safe publication occurs after the read(...) completes.

like image 38
user16762403 Avatar answered Sep 21 '22 17:09

user16762403