AsynchronousFileChannel是Java NIO.2提供的基于操作系统异步I/O(如io_uring、I/OCP)的非阻塞文件通道,需通过open()创建,支持Future或CompletionHandler回调,position为绝对偏移量,须手动管理ByteBuffer状态、控制并发并显式关闭。

AsynchronousFileChannel 是 Java NIO.2 提供的异步文件通道,支持不阻塞线程的读写操作,适合高并发、I/O 密集型场景。它基于操作系统级别的异步 I/O(如 Linux 的 io_uring 或 Windows 的 I/O Completion Ports),但注意:JVM 实现可能回退为线程池模拟(比如在不支持原生 AIO 的系统上)。
创建 AsynchronousFileChannel 实例
不能直接 new,需通过静态工厂方法打开:
- 读取文件:
AsynchronousFileChannel.open(path, StandardOpenOption.READ) - 写入文件:
AsynchronousFileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE) - 追加写入:
StandardOpenOption.APPEND替代WRITE - 可指定自定义线程池:
AsynchronousFileChannel.open(path, opts, executor),否则用默认的 ForkJoinPool.commonPool()
异步读取:使用 CompletionHandler
调用 read(ByteBuffer, position, attachment, handler),读取从指定位置开始的数据:
-
ByteBuffer必须已分配且clear()(不能是只读或已满状态) -
position是文件中的起始偏移量(字节),从 0 开始 -
attachment是任意对象,传入后可在回调中获取(常用来传递上下文,如 channel 或 buffer) -
handler是CompletionHandler<Integer, Object>,Integer表示实际读取字节数(-1 表示 EOF)
示例片段:
立即学习“Java免费学习笔记(深入)”;
ByteBuffer buf = ByteBuffer.allocate(1024);
channel.read(buf, 0, channel, new CompletionHandler<Integer, AsynchronousFileChannel>() {
@Override
public void completed(Integer result, AsynchronousFileChannel attachment) {
buf.flip();
byte[] data = new byte[buf.remaining()];
buf.get(data);
System.out.println("读到:" + new String(data));
buf.clear();
}
@Override
public void failed(Throwable exc, AsynchronousFileChannel attachment) {
exc.printStackTrace();
}
});
异步写入:类似读取,注意 position 和 buffer 状态
write(ByteBuffer, position, attachment, handler) 同样是非阻塞:
- 写入前确保
ByteBuffer已flip()(limit 设为待写长度,position=0) -
position指定写入起始位置;若文件未达该位置,中间会补零(类似 seek + write) - 若用
APPEND打开,则position被忽略,总是追加到末尾 - 回调中
result是实际写入字节数,一般等于 buffer 中剩余字节
使用 Future 方式(更简洁,适合简单场景)
如果不想写完整回调,可用返回 Future<Integer> 的重载方法:
-
read(buf, position)→ 返回Future<Integer> -
write(buf, position)→ 同样返回Future<Integer> - 调用
future.get()会阻塞等待完成(失去异步意义),建议仅用于测试或单次同步等待 - 更合理做法是配合
CompletableFuture转换:CompletableFuture.supplyAsync(() -> future.get(), executor)
关闭与资源管理
AsynchronousFileChannel 实现 AutoCloseable,务必显式 close() 或用 try-with-resources:
- 未关闭会导致文件句柄泄漏,尤其在频繁打开/关闭时
- 关闭后所有未完成的 I/O 操作会立即失败(抛
ClosedChannelException) - 注意:关闭不等待正在执行的异步操作完成,只是取消后续提交
注意事项与常见坑
- 多个线程可安全共享同一 channel,但同一时刻对同一个 buffer 调用 read/write 可能出错 —— 建议每个操作用独立 buffer
- position 是文件偏移,不是 buffer 位置;buffer 的 position/limit 需手动控制(flip/clear)
- Windows 上 AIO 性能较好;Linux 默认使用线程池模拟(可通过 JVM 参数
-Djava.nio.channels.spi.DefaultSelectorProvider=sun.nio.ch.EPollSelectorProvider优化,但底层仍是多路复用,非真正异步) - 大文件分块读写时,注意 buffer 大小和 position 计算,避免覆盖或跳过数据


















