ZOFTINO.COM android and web dev tutorials

Java Asynchronous IO NIO2

Like asynchronous programming used for any other operations, asynchronous IO makes it possible for a program to perform other operations while performing IO operations or execute multiple IO operation concurrently. Asynchronous IO uses threads and processes to perform concurrent operations.

Asynchronous IO is different from non blocking IO. Non blocking IO depends on operating system feature which allows programs to read whatever the data that is available without waiting while OS gathers more data. Program checks for availability of data using selectors. Non blocking IO uses single thread. In blocking IO, program uses single thread and waits for the OS to read data. For more information about selector and non blocking IO, see Java NIO examples.

NIO2 Asynchronous API

Java NIO2 API provides asynchronous channels such as AsynchronousSocketChannel, AsynchronousServerSocketChannel, AsynchronousFileChannel and AsynchronousDatagramChannel. Like corresponding non asynchronous channels, asynchronous channels provide similar operations, but they also provide methods to run operations asynchronously.

Asynchronous operations exist in two forms, one form returns Future object which represents results and second form takes CompletionHandler object and executes completed method on the handler object after operation is complete.

Using the Future object returned from an asynchronous operation, you can check for completion of the operation using isDone() and retrieve the result using get() methods. Future object allows you to cancel the initiated operation calling cancel() method on future object.

CompletionHandler is an interface which has completed() and failed() methods. You need to implement these methods to process results and failure scenarios. To use handler form of asynchronous operation, you need to pass CompletionHandler object to asynchronous operations.

AsynchronousServerSocketChannel Server Example

Following example shows how to use AsynchronousServerSocketChannel which contains accept() asynchronous operation. The example repeatedly listens for client connections and perform read and write asynchronous operations AsynchronousSocketChannel object.

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.util.concurrent.Future;

public class AsynchronousIOServer {

	private int port = 8080;

	public static void main(String[] args) {
		//run server
		AsynchronousIOServer server = new AsynchronousIOServer();
		server.startAsyncServer();
	}
	//starts server and listens for client connect
	public void startAsyncServer() {

		try {
			AsynchronousServerSocketChannel assc =  
					AsynchronousServerSocketChannel.open()
					.bind(new InetSocketAddress(port));
			
			while(true) {
				
				//get future object which returns AsynchronousSocketChannel
				Future<AsynchronousSocketChannel> socketFuture = assc.accept();

				//check if client connection is available, if not sleep
				while(!socketFuture.isDone()) {
					//sleep or do something else
					Thread.sleep(200);				
				}

				//get AsynchronousSocketChannel 
				//object from Future object using get
				AsynchronousSocketChannel asc = socketFuture.get();

				//read data from client
				ByteBuffer bb = ByteBuffer.allocate(1200);
				int byteCount = asc.read(bb).get();			
				System.out.println("bytes read from client "+byteCount);

				bb.flip();
				String clientInput = Charset.defaultCharset().
						decode(bb).toString();
				System.out.println(clientInput);


				//write response to client
				ByteBuffer bbOut = ByteBuffer.wrap("take the info".getBytes());
				bbOut.rewind();
				//write asynchronous operation using CompletionHandler
				asc.write(bbOut, null, new CompletionHandler<Integer, Object>() {
					@Override
					public void completed(Integer result, Object attachment) {
						System.out.println("number of bytes sent to client "
								+ result);
					}
					@Override
					public void failed(Throwable exc, Object attachment) {
						System.out.println("failed to send resp"
								+ attachment);
					}				
				});
				Thread.sleep(1000);
				asc.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

AsynchronousSocketChannel Client Example

Following example shows how to use AsynchronousSocketChannel. It performs connect(), read() and write() operations in asynchronous way. It shows how to handle response from these asynchronous operations using Future and CompletionHandler objects.

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class AsynchronousIOClient {
	private int port = 8080;
	private String hostName = "localhost";

	public static void main(String[] args) {
		//start client
		AsynchronousIOClient client = new AsynchronousIOClient();
		client.sendRequest("send info");
	}

	public void sendRequest(String request) {
		try {
			AsynchronousSocketChannel asc = AsynchronousSocketChannel.open();

			InetSocketAddress addr = new InetSocketAddress(hostName, port);		 
			Future<Void> conn = asc.connect(addr);

			//check if connected to server
			while(!conn.isDone()) {
				//do something
				//or sleep
				Thread.sleep(20);
			}

			//send request using write asynchronous operation
			byte reqb[] = request.getBytes();
			ByteBuffer bb = ByteBuffer.allocate(reqb.length);
			bb.put(request.getBytes());
			bb.rewind();

			Future<Integer> writeFuture = asc.write(bb);
			int count  = writeFuture.get(30, TimeUnit.MILLISECONDS);
			System.out.println("byte sent to server "+count);

			//getResponse using read asynchronous operation and completion handler
			ByteBuffer bbr = ByteBuffer.allocate(100);
			asc.read(bbr, null, new CompletionHandler<Integer, Object>() {
				@Override
				public void completed(Integer result, Object attachment) {
					bbr.flip();
					System.out.println("response from server "+result+" "
							+Charset.defaultCharset()
							.decode(bbr).toString());
				}
				@Override
				public void failed(Throwable exc, Object attachment) {
					System.out.println("failed to get response from server ");
				}				
			});
			
			Thread.sleep(1000);
			asc.close();
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}

AsynchronousFileChannel Example

AsynchronousFileChannel is similar to FileChannel except that it provides asynchronous read, write and lock methods.

Following example shows how to read data from a file using AsynchronousFileChannel using asynchronous read operation. Asynchronous read operation exist in two form one uses Future object and other one uses CompletionHandler object. First you need to open AsynchronousFileChannel calling open method and passing path and open options.

Then create CompletionHandler to be used with read operation. In the implementation of completed method, get data from the byte buffer, if end of the file is not reached, clear the buffer and call asynchronous read operation again setting position.

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class AsynchronousFileReader {
	private int bufferCapacity = 100;
	private int position = 0;
	private ByteBuffer bb =  ByteBuffer.allocate(bufferCapacity);
	
	public static void main(String[] args) {
		AsynchronousFileReader afr = new AsynchronousFileReader();
		afr.readFileAsynchronously("/dev/java/core/app/offers.txt");
	}
	public void readFileAsynchronously(String file) {
		Charset charset = Charset.forName("UTF-8");
		Path filePath = Paths.get(file);
		
		try {
			AsynchronousFileChannel afc = AsynchronousFileChannel
					.open(filePath, StandardOpenOption.READ);
				
			System.out.println("file size "+afc.size());
			
			//completion handler
			CompletionHandler<Integer, ByteBuffer> ch = 
					new CompletionHandler<Integer, ByteBuffer>() {
				@Override
				public void completed(Integer result, ByteBuffer attachment) {
					try {
						bb.flip();
						System.out.println("bytea red "+bb.limit());
						System.out.println(charset.decode(bb).toString());
						
						//read if end of the file is not reached
						if(afc.size() > position) {
							position = position + bb.limit();
							bb.clear();
							//pass the same completion handler
							afc.read(bb, position, bb, this);
						}
					} catch (IOException e) {
						e.printStackTrace();
						System.out.println("failed to read at: "+position);
					}		
				}
				@Override
				public void failed(Throwable exc, ByteBuffer attachment) {
					System.out.println("failed to read at: "+position);
				}				
			};			
			
			//read data asynchronously using CompletionHandler
			afc.read(bb, position, bb, ch);
			
			//do something else while file is being read async
			Thread.sleep(2000);
			
		} catch (Exception e) {

		}
	}
}

Following example shows writing file asynchronously.

	public void writeFileAsynchronously() {
		Path filePath = Paths.get(file);
		try {
			AsynchronousFileChannel afc = AsynchronousFileChannel
					.open(filePath, 
					StandardOpenOption.WRITE);
			
			byte dealb[] = "upto 10% off on fashion".getBytes();
			ByteBuffer bb =  ByteBuffer.wrap(dealb);			

			Future<Integer> f = afc.write(bb, 0);
			int bytesWritten = f.get(20, TimeUnit.MILLISECONDS);
			
			System.out.println("bytes written "+bytesWritten);
			
		} catch (Exception e) {

		}
	}

Other Tutorials Related to IO