Recently I had a requirement to work with lot of I/O type of work and at the same time a lot of computation.So what Immediately a solution comes to mind that we will start a configurable number of threads.And the job of each thread will do the I/O independently and then after start the computation.But here one thing to observe that my computation has a very little to do with the I/O.But in this design my thread is not doing any useful when it is doing the I/O and after the completion of the I/O the thread is going for computation.But it would be great if my thread can be free once it starts the I/O and without waiting to complete the I/O jumps to the computation part.And some one informs my thread once the I/O completes.Till that my thread is busy with doing some useful calculation.
So here we get the two benefits.My thread is not waiting for I/O to complete and at the same time , it is doing some useful calculation.Here note that the job of my thread is both I/O bound and CPU bound.
NIO.2 provides support for asynchronous I/O(connecting, reading, and writing). In a synchronous I/O, the thread that requests the I/O operation waits until the I/O operation completes.In an asynchronous I/O, the application requests the system for an I/O operation and the operation is performed by the system asynchronously. When the system is performing the I/O operation, the application continues doing some other useful computation work. When the system finishes the I/O, it notifies the application about the completion of I/O operation.
Four asynchronous channels are added in NIO.2 (java 7) to the java.nio.channels package:
The AsynchronousFileChannel provides us two different ways for monitoring and controlling the initiated asynchronous operations.
The first one is by returning a java.util.concurrent.Future object, which poses a Future object and can be used to enquire its state and obtain the result.It follows a poll type approach.
The second is by passing to the I/O operation an object of a new class, java.nio.channels.CompletionHandler, which defines handler methods that are executed after the operation is completed.It follows a push type approach.
Each method of the AsynchronousFileChannel class that supports asynchronous file I/O operation has two versions.One for Future object and another for CompletionHandler object.
In the example above first we create an AsynchronousFileChannel for writting. Then we use the write method to write some data,which return a Future object. Once we get a Future object, we use a polling method method to handle the result of the asynchronous file I/O, where it keeps calling the isDone() method of the Future object to check if the I/O operation is finished or not.And rest of the code is self explanatory.But note that while checking the result of future object we are taking a 1 second sleep, but in real life we we will do some useful calculation there.
This version of the write method of the AsynchronousFileChannel class allows us pass a CompletionHandler object whose methods are called when the requested asynchronous I/O operation completes or fails.
CompletionHandler interface is defined in the java.nio.channels package.
The type parameters:
V – The result type of the I/O operation
A – The type of the object attached to the I/O operation
The CompletionHandler interface has two methods: completed() and failed(). The completed() method is called when the requested I/O operation completes successfully. the failed() method is called ,when the requested I/O operation fails. The API allows us to pass an object of any type to the completed() and failed() methods. Such an object is called an attachment.We may want to pass an attachment such as the ByteBuffer or the reference to the channel or an reference to the I/O source etc. to these methods such that we can perform additional actions inside these methods.For example we want to close the AsynchronousFileChannel once the async I/O operation completes successfully or fails due to any reason.We can also pass null as an attachment , if we don't want to do anything usefull.
Lets create an Attachment object first
Now let's define the CompletionHandler
Here the main thread is sleeping for 10 seconds ,but in real life scenario , the main thread will do some useful calculation rather than sleeping.
So here we get the two benefits.My thread is not waiting for I/O to complete and at the same time , it is doing some useful calculation.Here note that the job of my thread is both I/O bound and CPU bound.
Asynchronous I/O :
NIO.2 provides support for asynchronous I/O(connecting, reading, and writing). In a synchronous I/O, the thread that requests the I/O operation waits until the I/O operation completes.In an asynchronous I/O, the application requests the system for an I/O operation and the operation is performed by the system asynchronously. When the system is performing the I/O operation, the application continues doing some other useful computation work. When the system finishes the I/O, it notifies the application about the completion of I/O operation.
Four asynchronous channels are added in NIO.2 (java 7) to the java.nio.channels package:
- AsynchronousSocketChannel
- AsynchronousServerSocketChannel
- AsynchronousFileChannel
- AsynchronousDatagramChannel
The AsynchronousFileChannel provides us two different ways for monitoring and controlling the initiated asynchronous operations.
The first one is by returning a java.util.concurrent.Future object, which poses a Future object and can be used to enquire its state and obtain the result.It follows a poll type approach.
The second is by passing to the I/O operation an object of a new class, java.nio.channels.CompletionHandler, which defines handler methods that are executed after the operation is completed.It follows a push type approach.
Each method of the AsynchronousFileChannel class that supports asynchronous file I/O operation has two versions.One for Future object and another for CompletionHandler object.
Example of poll approach using Future object:
package com.brainatjava.test;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.WRITE;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.Future;
public class AshyncronousIOWithFuture {
static String str="write some meaning full text to file,which is desired for your applications.";
public static void main(String[] args) {
long startPosition=0;
Path path = Paths.get("/home/brainatjava/mytest");
try (AsynchronousFileChannel asyncFileChannel =
AsynchronousFileChannel.open(path, WRITE, CREATE)) {
ByteBuffer dataBuffer = ByteBuffer.wrap(str.getBytes());
Future result = asyncFileChannel.write(dataBuffer, startPosition);
while (!result.isDone()) {
try {
//remember in real life scenario the initiating thread will not sleep but it will do some useful work.
System.out.println("Sleeping for one seconds before the next pooling.We will continue to keep pooling in each one second.");
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Now I/O operation is complete and we are going to get the result.");
try {
int resultbytewritten = result.get();
System.out.format("%s bytes written to %s%n",
resultbytewritten, path.toAbsolutePath());
}
catch (Exception e) {
e.printStackTrace();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
In the example above first we create an AsynchronousFileChannel for writting. Then we use the write method to write some data,which return a Future object. Once we get a Future object, we use a polling method method to handle the result of the asynchronous file I/O, where it keeps calling the isDone() method of the Future object to check if the I/O operation is finished or not.And rest of the code is self explanatory.But note that while checking the result of future object we are taking a 1 second sleep, but in real life we we will do some useful calculation there.
Example of push approach using CompletionHandler object:
This version of the write method of the AsynchronousFileChannel class allows us pass a CompletionHandler object whose methods are called when the requested asynchronous I/O operation completes or fails.
CompletionHandler interface is defined in the java.nio.channels package.
The type parameters:
V – The result type of the I/O operation
A – The type of the object attached to the I/O operation
The CompletionHandler interface has two methods: completed() and failed(). The completed() method is called when the requested I/O operation completes successfully. the failed() method is called ,when the requested I/O operation fails. The API allows us to pass an object of any type to the completed() and failed() methods. Such an object is called an attachment.We may want to pass an attachment such as the ByteBuffer or the reference to the channel or an reference to the I/O source etc. to these methods such that we can perform additional actions inside these methods.For example we want to close the AsynchronousFileChannel once the async I/O operation completes successfully or fails due to any reason.We can also pass null as an attachment , if we don't want to do anything usefull.
Lets create an Attachment object first
public class Attachment {
private Path filesource;
private AsynchronousFileChannel asyncChannel;
//getters and setters goes here.
}
Now let's define the CompletionHandler
private static class MyWriteCompletionHandler
implements CompletionHandler {
@Override
public void completed(Integer result, Attachment attachment) {
System.out.format("%s bytes written to %s%n",
result, attachment.path.toAbsolutePath());
try {
attachment.asyncChannel.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable e, Attachment attachment) {
System.out.format("I/O operation on %s file failed." +
"with error is: %s", attachment.path, e.getMessage());
try {
attachment.asyncChannel.close();
}
catch (IOException e1) {
e1.printStackTrace();
}
}
}
public class ASyncIOWithCompletionHandler{
public static void main(String[] args) {
static String str="write some meaning full text to file,which is desired for your applications.";
Path path = Paths.get("/home/brainatjava/mytest");
try {
AsynchronousFileChannel asyncfileChannel =
AsynchronousFileChannel.open(path, WRITE,CREATE);
MyWriteCompletionHandler handler = new MyWriteCompletionHandler();
ByteBuffer dataBuffer = ByteBuffer.wrap(str.getBytes());
Attachment attachment = new Attachment();
attachment.setAsyncChannel(asyncfileChannel);
attachment.setPath(path);
asyncfileChannel.write(dataBuffer, 0, attachment, handler);
try {
System.out.println("Sleeping for 10 seconds...");
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Completed");
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Here the main thread is sleeping for 10 seconds ,but in real life scenario , the main thread will do some useful calculation rather than sleeping.
Nice informative content. Thanks for sharing the valuable information.
ReplyDeleteUnix Training in Chennai
Node JS Training in Chennai
Unix shell scripting Training in Chennai
Node JS Course in Chennai
Unix Course in Chennai
Node JS Training Institute in chennai
Unix Training Institutes in Chennai