Search code examples
javaasynchronousnonblocking

non-blocking IO vs async IO and implementation in Java


Trying to summarize for myself the difference between these 2 concepts (because I'm really confused when I see people are using both of them in one sentence, like "non-blocking async IO" which I'm trying to figure out what does it mean).

So, in my understanding non-blocking IO is primary the OS mechanism to process the IO if there is any data ready, otherwise just return error/do nothing.

In async IO you just provide a callback, and your application will be notified when the data is available.

So what is actually "non-blocking async IO"? And how all them can be implemented in Java (standard JDK, without external libs, I know there are java.nio.channels.{Channels, Selector, SelectorKey} and java.nio.channels.{AsynchronousSocketChannel}): non-blocking IO, async IO, and non-blocking async IO (if there is such thing)?


Solution

  • So what is actually "non-blocking async IO"?

    To answer that, you must first understand that there's no such thing as blocking async I/O. The very concept of asynchronism dictates that there's no waiting, no blocking, no delay. When you see non-blocking asynchronous I/O, the non-blocking bit only serves to further qualify the async adjective in that term. So effectively, non-blocking async I/O might be a bit of a redundancy.

    There are mainly two kinds of I/O. Synchronous and Asynchronous. Synchronous blocks the current thread of execution until processing is complete, while Asynchronous doesn't block the current thread of execution, rather passing control to the OS Kernel for further processing. The kernel then advises the async thread when the submitted task is complete


    Asynchronous Channel Groups

    The concept of Async Channels in java is backed by Asynchronous Channel Groups. An async channel group basically pools a number of channels for reuse. Consumers of the async api retrieve a channel from the group (the JVM creates one by default) and the channel automatically puts itself back into the group after it's completed its read/write operation. Ultimately, Async Channel Groups are backed by surprise, threadpools. Also, Asynchronous channels are threadsafe.

    The size of the threadpool that backs an async channel group is configured by the following JVM property

    java.nio.channels.DefaultThreadPool.initialSize
    

    which, given an integer value will setup a threadpool of that size, to back the channel group. The channel group is created and maintained transparently to the developer otherwise.


    And how all them can be implemented in Java

    Well, I'm glad you asked. Here's an example of an AsynchronousSocketChannel (used to open a non-blocking client Socket to a listening server.) This sample is an excerpt from Apress Pro Java NIO.2, commented by me:

    //Create an Asynchronous channel. No connection has actually been established yet
    AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open(); 
    
    /**Connect to an actual server on the given port and address. 
       The operation returns a type of Future, the basis of the all 
       asynchronous operations in java. In this case, a Void is 
       returned because nothing is returned after a successful socket connection
      */
    Void connect = asynchronousSocketChannel.connect(new InetSocketAddress("127.0.0.1", 5000)).get();
    
    
    //Allocate data structures to use to communicate over the wire
    ByteBuffer helloBuffer = ByteBuffer.wrap("Hello !".getBytes()); 
    
    //Send the message
    
    Future<Integer> successfullyWritten=  asynchronousSocketChannel.write(helloBuffer);
    
    //Do some stuff here. The point here is that asynchronousSocketChannel.write() 
    //returns almost immediately, not waiting to actually finish writing 
    //the hello to the channel before returning control to the currently executing thread
    
    doSomethingElse();
    
    //now you can come back and check if it was all written (or not)
    
    System.out.println("Bytes written "+successfullyWritten.get());
    

    EDIT: I should mention that support for Async NIO came in JDK 1.7