Руководство по API NIO2 для асинхронных каналов Java

Руководство по API асинхронного канала Java NIO2

1. обзор

В этой статье мы собираемся изучить основы одного из ключевых дополнительных API-интерфейсов нового ввода-вывода (NIO2) в Java 7-asynchronous channel APIs.

Это первая в серии статей, которые будут освещать эту конкретную тему.

API-интерфейсы асинхронного канала являются усовершенствованием более ранних новых API-интерфейсов ввода-вывода (NIO), которые поставлялись с Java 1.4. Чтобы прочитать о селекторах NIO, следуйтеthis link.

Еще одним усовершенствованием API-интерфейсов NIO является новый API-интерфейс файловой системы. Вы также можете узнать больше о егоfile operations иpath operations на этом сайте.

Чтобы использовать асинхронные каналы NIO2 в наших проектах, мы должны импортировать пакетjava.nio.channels, поскольку в него включены необходимые классы:

import java.nio.channels.*;

2. Как работают API асинхронного канала

API асинхронного канала были введены в существующий пакетjava.nio.channels, проще говоря - путем добавления к именам классов префиксаAsynchronous.

Некоторые из основных классов включают:AsynchronousSocketChannel,AsynchronousServerSocketChannel иAsynchronousFileChannel.

Как вы, возможно, заметили, эти классы похожи по стилю на стандартные API канала NIO.

И большинство операций API, доступных для классов каналов NIO, также доступны в новых асинхронных версиях. Основное отличие состоит в том, чтоthe new channels enable some operations to be executed asynchronously.

Когда операция инициируется, API-интерфейсы асинхронного канала предоставляют нам две альтернативы для мониторинга и управления ожидающими операциями. Операция может вернуть объектjava.util.concurrent.Future или мы можем передать емуjava.nio.channels.CompletionHandler.

3. ПодходFuture

A Future object represents a result of an asynchronous computation. Предполагая, что мы хотим создать сервер для прослушивания клиентских подключений, мы вызываем статический APIopen дляAsynchronousServerSocketChannel и, при необходимости, привязываем возвращенный канал сокета к адресу:

AsynchronousServerSocketChannel server
  = AsynchronousServerSocketChannel.open().bind(null);

Мы передалиnull, чтобы система могла автоматически назначать адрес. Затем мы вызываем методaccept на возвращенном сервереSocketChannel:

Future future = server.accept();

Когда мы вызываем методaccept дляServerSocketChannel в старом IO, он блокируется до тех пор, пока не будет получено входящее соединение от клиента. Но методaccept дляAsynchronousServerSocketChannel сразу возвращает объектFuture.

Универсальный тип объектаFuture - это тип, возвращаемый операцией. В нашем случае выше этоAsynchronousSocketChannel, но с тем же успехом это могло бытьInteger илиString, в зависимости от конечного типа возврата операции.

Мы можем использовать объектFuture для запроса состояния операции:

future.isDone();

Этот API возвращаетtrue, если базовая операция уже завершена. Обратите внимание, что завершение в этом случае может означать нормальное завершение, исключение или отмену.

Мы также можем явно проверить, была ли операция отменена:

future.isCancelled();

Он возвращаетtrue только в том случае, если операция была отменена до нормального завершения, в противном случае возвращаетсяfalse. Отмена производится методомcancel:

future.cancel(true);

Вызов отменяет операцию, представленную объектомFuture. Параметр указывает, что даже если операция началась, она может быть прервана. После завершения операции ее нельзя отменить.

Чтобы получить результат вычисления, мы используем методget:

AsynchronousSocketChannel client= future.get();

Если мы вызовем этот API до завершения операции, он будет блокирован до завершения, а затем вернет результат операции.

4. ПодходCompletionHandler

Альтернативой использованию Future для обработки операций является механизм обратного вызова с использованием классаCompletionHandler. Асинхронные каналы позволяют указывать обработчик завершения для использования результата операции:

AsynchronousServerSocketChannel listener
  = AsynchronousServerSocketChannel.open().bind(null);

listener.accept(
  attachment, new CompletionHandler() {
    public void completed(
      AsynchronousSocketChannel client, Object attachment) {
          // do whatever with client
      }
    public void failed(Throwable exc, Object attachment) {
          // handle failure
      }
  });

API обратного вызоваcompleted вызывается после успешного завершения операции ввода-вывода. Обратный вызовfailed вызывается, если операция не удалась.

Эти методы обратного вызова принимают другие параметры - чтобы мы могли передавать любые данные, которые, по нашему мнению, могут быть пригодны для тегирования вместе с операцией. Этот первый параметр доступен как второй параметр метода обратного вызова.

Наконец, ясный сценарий - использование одного и того жеCompletionHandler для разных асинхронных операций. В этом случае нам было бы полезно пометить каждую операцию, чтобы обеспечить контекст при обработке результатов, мы увидим это в действии в следующем разделе.

5. Заключение

В этой статье мы изучили вводные аспекты API асинхронного канала в Java NIO2.

Чтобы получить все фрагменты кода и полный исходный код для этой статьи, вы можете посетитьGitHub project.