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 .