Java AIO通过AsynchronousChannel系列类和CompletionHandler实现异步非阻塞IO,由OS通知完成并触发回调;CompletionHandler<V,A>中V为结果类型、A为上下文附件,含completed与failed两个方法;需注意线程池调用、handler一次性、-1 EOF处理及ByteBuffer正确翻转与清理。

Java 中的 AIO(Asynchronous I/O,异步非阻塞 IO)通过 java.nio.channels.AsynchronousChannel 系列类实现,核心是使用 CompletionHandler 处理异步操作完成后的回调逻辑。它不依赖轮询或显式线程阻塞,而是由操作系统底层通知 JVM 操作完成,再触发你定义的回调。
CompletionHandler 接口结构与作用
CompletionHandler<V,A> 是一个泛型接口,两个类型参数含义如下:
-
V:异步操作的返回结果类型,如
Integer(读/写字节数)、Void(连接操作) -
A:附加对象(attachment),用于在发起异步调用时传入上下文信息,比如
ByteBuffer、自定义会话对象等
它定义两个方法:
-
completed(V result, A attachment):操作成功完成时被调用 -
failed(Throwable exc, A attachment):操作失败时被调用
以 AsynchronousSocketChannel 为例:异步连接 + 读写
下面是一个简化的客户端示例,演示如何用 CompletionHandler 实现连接、发送、接收全流程:
立即学习“Java免费学习笔记(深入)”;
1. 建立异步连接
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(new InetSocketAddress("localhost", 8080), null,
new CompletionHandler<Void, Void>() {
@Override
public void completed(Void result, Void attachment) {
System.out.println("连接成功");
// 启动异步读取
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer, buffer, new ReadHandler(channel));
}
@Override
public void failed(Throwable exc, Void attachment) {
System.err.println("连接失败: " + exc.getMessage());
}
});
2. 自定义 ReadHandler 处理读取完成
static class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {
private final AsynchronousSocketChannel channel;
ReadHandler(AsynchronousSocketChannel channel) {
this.channel = channel;
}
@Override
public void completed(Integer bytesRead, ByteBuffer buffer) {
if (bytesRead == -1) {
System.out.println("对端关闭连接");
closeChannel();
return;
}
buffer.flip();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
System.out.println("收到:" + new String(data).trim());
buffer.clear();
// 继续读
channel.read(buffer, buffer, this);
}
@Override
public void failed(Throwable exc, ByteBuffer buffer) {
System.err.println("读取失败:" + exc.getMessage());
closeChannel();
}
private void closeChannel() {
try { channel.close(); } catch (IOException ignored) {}
}
}
关键注意事项
-
CompletionHandler的方法由 系统线程池(ForkJoinPool.commonPool 或 AsynchronousChannelGroup 配置的线程池) 调用,不是你发起调用的线程 —— 所以不要假设线程上下文(如 ThreadLocal)一致 - 每次异步操作(如
read/write)都需重新提交 handler;它是一次性的,不会自动重复注册 - 务必检查
read返回值:-1表示 EOF(对端关闭),需主动关闭通道 - 缓冲区(
ByteBuffer)在回调中可能仍被内核使用,务必在completed中flip()后读取,并在继续下一次read前clear()或compact() - 推荐使用 lambda 简化 handler,但注意捕获变量不可变;复杂逻辑建议用静态内部类或独立类
替代方案:Future 方式(不推荐用于高并发场景)
除了 CompletionHandler,AIO 也支持返回 Future:
Future<Integer> future = channel.read(buffer); Integer bytesRead = future.get(); // 阻塞等待 —— 这就失去了“异步非阻塞”的意义
这种方式违背 AIO 设计初衷,仅适合简单测试或低频调用,生产环境应始终优先使用 CompletionHandler。


















