AsynchronousFileChannel 是 Java NIO.2 提供的异步文件通道,基于操作系统异步 I/O 实现,创建需用 open() 方法,支持回调式读写操作,但非线程安全且需注意资源关闭与回调耗时问题。

AsynchronousFileChannel 是 Java NIO.2 提供的异步文件通道,适合在不阻塞线程的前提下执行大文件读写,尤其适用于高并发 I/O 场景。它基于操作系统底层异步 I/O(如 Linux 的 io_uring 或 Windows 的 IOCP),但注意:JVM 实现可能回退为线程池模拟(比如 Linux 默认用 `ThreadPool` 模拟异步),实际是否真正异步取决于平台和 JVM 参数。
1. 创建 AsynchronousFileChannel 实例
不能直接 new,需通过 AsynchronousFileChannel.open() 获取。支持指定路径、打开选项(如读/写/追加)、文件属性及自定义线程池:
- 默认使用 ForkJoinPool.commonPool(),生产环境建议传入专用线程池,避免干扰其他异步任务
- 常用选项:
StandardOpenOption.READ、StandardOpenOption.WRITE、StandardOpenOption.CREATE、StandardOpenOption.TRUNCATE_EXISTING
示例:
AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get("data.txt"),
StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE,
AsynchronousFileChannel.defaultThreadPool());
2. 异步读取文件(带回调)
调用 read(ByteBuffer, position, attachment, handler),其中 handler 是 CompletionHandler<Integer, ?>,Integer 表示本次读到的字节数(-1 表示 EOF):
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- ByteBuffer 必须已分配且
flip()前要clear()(每次读前重置) -
position是文件内偏移量,不影响通道内部指针(与 FileInputStream 不同) -
attachment可传任意对象(如 ByteBuffer 或上下文),在回调中可获取
示例(读取前 1024 字节):
ByteBuffer buf = ByteBuffer.allocate(1024);channel.read(buf, 0, buf, new CompletionHandler<Integer, ByteBuffer>() {
public void completed(Integer result, ByteBuffer attachment) {
if (result == -1) {
System.out.println("读到文件末尾");
return;
}
attachment.flip();
byte[] data = new byte[attachment.remaining()];
attachment.get(data);
System.out.println("读到:" + new String(data));
}
public void failed(Throwable exc, ByteBuffer attachment) {
exc.printStackTrace();
}
});
3. 异步写入文件(带回调)
写法类似 read,用 write(ByteBuffer, position, attachment, handler):
- 写入位置
position若超出当前文件长度,中间会补零(类似随机写) - 若希望追加,需先调用
size()获取长度,再以该值为 position 写入 - ByteBuffer 需已
flip()(即 limit ≤ capacity,position=0)
示例(从文件末尾追加):
String content = "Hello Async!";ByteBuffer buf = ByteBuffer.wrap(content.getBytes());
channel.size().thenAccept(size -> {
channel.write(buf, size, null, new CompletionHandler<Integer, Void>() {
public void completed(Integer result, Void attachment) {
System.out.println("写入完成,字节数:" + result);
}
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
});
4. 注意事项与常见陷阱
- AsynchronousFileChannel 不是线程安全的,但多个线程可同时发起不同操作(因每个操作独立回调)
- 不要在 CompletionHandler 中做耗时操作(如数据库写入、HTTP 调用),否则会阻塞线程池;应交由其他线程或 Executor 处理
- 务必关闭 channel(
channel.close()),否则可能泄漏文件句柄 - 异步操作不保证执行顺序,多次 write 到同一区域可能产生竞态;如需顺序写,应串行化操作(例如链式回调或 CompletableFuture.thenCompose)
- 小文件或低频操作,同步 FileChannel 更简单高效;异步优势体现在大量并发 I/O 场景

















