Перейти к основному содержимому

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

· 4 мин. чтения

1. Обзор

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

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

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

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

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

import java.nio.channels.*;

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

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

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

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

И большинство операций API, доступных для классов каналов NIO, также доступны в новых асинхронных версиях. Основное отличие состоит в том, что новые каналы позволяют выполнять некоторые операции асинхронно .

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

3. Будущий подход

Объект Future представляет собой результат асинхронного вычисления. Предполагая, что мы хотим создать сервер для прослушивания клиентских подключений, мы вызываем статический открытый API в AsynchronousServerSocketChannel и при необходимости привязываем возвращенный канал сокета к адресу:

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

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

Future<AsynchronousSocketChannel> 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. Подход с обработчиком завершения

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

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

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

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

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

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

5. Вывод

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

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