1. 概述
在本文中,我们将探讨Java 7中新增的NIO2(New I/O)API之一——异步通道API的基础知识。这将是关于此特定主题的一系列文章的第一篇。
异步通道API是对Java 1.4中随NIO一起发布的早期新IO API的增强。有关NIO选择器的详细信息,请参阅此处。
NIO API的另一个增强是新的文件系统API。您也可以在这个网站上了解更多关于其文件操作和路径操作的内容。
要在项目中使用NIO2的异步通道,我们需要导入java.nio.channels
包,因为所需的类都包含在其中:
import java.nio.channels.*;
2. 异步通道API的工作原理
异步通道API被引入到现有的java.nio.channels
包中,简单来说,就是通过在类名前加上“异步”前缀实现的。
一些核心类包括:AsynchronousSocketChannel
、AsynchronousServerSocketChannel
和AsynchronousFileChannel
。
您可能已经注意到,这些类的风格类似于标准的NIO通道API。
而且,大部分可用在NIO通道类上的API操作也适用于新的异步版本。主要的区别在于,新的通道允许某些操作异步执行。
当我们发起一个操作时,异步通道API为我们提供了两种监控和控制待处理操作的方式。操作可以返回java.util.concurrent.Future
对象,或者我们可以传递一个java.nio.channels.CompletionHandler
。
3. Future
方法
Future
对象表示异步计算的结果。假设我们要创建一个服务器来监听客户端连接,我们会调用AsynchronousServerSocketChannel
的静态open
方法,并可选地将返回的套接字通道绑定到一个地址:
AsynchronousServerSocketChannel server
= AsynchronousServerSocketChannel.open().bind(null);
我们传入null
,以便系统自动分配地址。然后,我们在返回的服务器SocketChannel
上调用accept
方法:
Future<AsynchronousSocketChannel> future = server.accept();
在旧IO中,调用ServerSocketChannel
的accept
方法会阻塞,直到接收到来自客户端的连接。但是,AsynchronousServerSocketChannel
的accept
方法会立即返回一个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<AsynchronousSocketChannel, Object>() {
public void completed(
AsynchronousSocketChannel client, Object attachment) {
// do whatever with client
}
public void failed(Throwable exc, Object attachment) {
// handle failure
}
});
当I/O操作成功完成时,completed
回调会被调用。如果操作失败,将调用failed
回调。
这些回调方法接受其他参数,以允许我们传递任何我们认为适合与操作关联的数据。这个第一个参数作为回调方法的第二个参数提供。
最后,一个明显的场景是——使用同一个CompletionHandler
处理不同的异步操作。在这种情况下,我们将在后续部分看到,通过标记每个操作来提供处理结果时的上下文将大有裨益。
5. 总结
在本文中,我们探讨了Java NIO2异步通道API的入门知识。
要获取本文的所有代码片段和完整源代码,请访问GitHub项目。