Java NIO - AsynchronousFileChannel

Como sabemos, o Java NIO suporta simultaneidade e multi-threading, o que nos permite lidar com diferentes canais simultaneamente ao mesmo tempo. Portanto, a API responsável por isso no pacote Java NIO é AsynchronousFileChannel, que é definido no pacote de canais NIO. para AsynchronousFileChannel é java.nio.channels.AsynchronousFileChannel.

AsynchronousFileChannel é semelhante ao FileChannel do NIO, exceto que este canal permite que as operações de arquivo sejam executadas de forma assíncrona, ao contrário da operação de E / S síncrona em que um thread entra em uma ação e espera até que a solicitação seja concluída. Assim, os canais assíncronos são seguros para uso por vários threads simultâneos.

No assíncrono, a solicitação é passada por thread para o kernel do sistema operacional para que seja realizada enquanto a thread continua a processar outro trabalho. Uma vez que o trabalho do kernel é feito, ele sinaliza a thread, então a thread reconhece o sinal e interrompe a tarefa atual e processa o Trabalho de E / S conforme necessário.

Para alcançar a simultaneidade, este canal oferece duas abordagens, incluindo uma como o retorno java.util.concurrent.Future object e outro é passar para a operação um objeto do tipo java.nio.channels.CompletionHandler.

Vamos entender ambas as abordagens com a ajuda de exemplos um por um.

  • Future Object - Neste, uma instância da Interface Futura é retornada do canal. Na interface Futura, há get() método que retorna o status da operação que é tratada de forma assíncrona com base na qual a execução posterior de outra tarefa pode ser decidida. Também podemos verificar se a tarefa foi concluída ou não chamando seu isDone método.

Exemplo

O exemplo a seguir mostra como usar o objeto Future e realizar tarefas de forma assíncrona.

package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
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.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class FutureObject {
   public static void main(String[] args) throws Exception {
      readFile();
   }
   private static void readFile() throws IOException, InterruptedException, ExecutionException {
      String filePath = "D:fileCopy.txt";
      printFileContents(filePath);
      Path path = Paths.get(filePath);		
      AsynchronousFileChannel channel =AsynchronousFileChannel.open(path, StandardOpenOption.READ);
      ByteBuffer buffer = ByteBuffer.allocate(400);
      Future<Integer> result = channel.read(buffer, 0); // position = 0
      while (! result.isDone()) {
         System.out.println("Task of reading file is in progress asynchronously.");
      }
      System.out.println("Reading done: " + result.isDone());
      System.out.println("Bytes read from file: " + result.get()); 
      buffer.flip();
      System.out.print("Buffer contents: ");
      while (buffer.hasRemaining()) {
         System.out.print((char) buffer.get());                
      }
      System.out.println(" ");
      buffer.clear();
      channel.close();
   }
   private static void printFileContents(String path) throws IOException {
      FileReader fr = new FileReader(path);
      BufferedReader br = new BufferedReader(fr);
      String textRead = br.readLine();
      System.out.println("File contents: ");
      while (textRead != null) {
         System.out.println("     " + textRead);
         textRead = br.readLine();
      }
   fr.close();
   br.close();
   }
}

Resultado

File contents: 
   To be or not to be?
   Task of reading file is in progress asynchronously.
   Task of reading file is in progress asynchronously.
   Reading done: true
   Bytes read from file: 19
   Buffer contents: To be or not to be?
  • Completion Handler -

    Esta abordagem é bastante simples, pois usamos a interface CompletionHandler e substitui seus dois métodos, um deles é completed() método que é chamado quando a operação de E / S é concluída com sucesso e outro é failed() método que é chamado se as operações de E / S falharem. Nesse caso, um manipulador é criado para consumir o resultado de uma operação de E / S assíncrona, uma vez que uma tarefa é concluída, apenas o manipulador tem funções que são executadas.

Exemplo

O exemplo a seguir mostra como usar CompletionHandler para realizar tarefas de maneira assíncrona.

package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class CompletionHandlerDemo {
   public static void main (String [] args) throws Exception {
      writeFile();
   }
   private static void writeFile() throws IOException {
      String input = "Content to be written to the file.";
      System.out.println("Input string: " + input);
      byte [] byteArray = input.getBytes();
      ByteBuffer buffer = ByteBuffer.wrap(byteArray);
      Path path = Paths.get("D:fileCopy.txt");
      AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
      CompletionHandler handler = new CompletionHandler() {
         @Override
         public void completed(Object result, Object attachment) {
            System.out.println(attachment + " completed and " + result + " bytes are written.");
         }
         @Override
         public void failed(Throwable exc, Object attachment) {
            System.out.println(attachment + " failed with exception:");
            exc.printStackTrace();
         }
      };
      channel.write(buffer, 0, "Async Task", handler);
      channel.close();
      printFileContents(path.toString());
   }
   private static void printFileContents(String path) throws IOException {
      FileReader fr = new FileReader(path);
      BufferedReader br = new BufferedReader(fr);
      String textRead = br.readLine();
      System.out.println("File contents: ");
      while (textRead != null) {
         System.out.println("     " + textRead);
         textRead = br.readLine();
      }
      fr.close();
      br.close();
   }
}

Resultado

Input string: Content to be written to the file.
Async Task completed and 34 bytes are written.
File contents: 
Content to be written to the file.