bigywater.tech
Java · 193

AsynchronousFileChannel:文件异步 I/O 的线程模型

文件的「异步 I/O」到底是不是真的异步?回调在哪个线程?这篇只验证线程模型与使用方式(没有对比真实磁盘的吞吐;内存映射与 WatchService 在前面的篇目)。

Thread-N 守护线程
默认线程池里 CompletionHandler 运行的线程
RejectedExecutionException
自定义线程池关闭后再发 read 的结果
262144 字节
64 个并发写共写入的字节数(内容全部正确)

默认线程池

实测 · 本机执行输出
  调用线程 = main;200 个并发 read 的 CompletionHandler 运行在这些线程名上:[Thread-N],是否守护线程:[true]
  此时除了 main 与 JVM 系统线程之外的线程数 = 17
  线程名:[Thread-0, Thread-1, Thread-10, Thread-11, Thread-12, Thread-13, Thread-14, Thread-15, Thread-16, Thread-2, Thread-3, Thread-4, Thread-5, Thread-6, Thread-7, Thread-8, Thread-9]

自定义线程池

实测 · 本机执行输出
  自定义线程池(2 个线程)时,CompletionHandler 的线程名 = [my-io-N]
  线程池 shutdown 之后再发 read:RejectedExecutionException

并发写与锁

实测 · 本机执行输出
  64 个并发的写(每个 4096 字节写到不同位置):共写入 262144 字节,耗时 1 ms
  读回校验:每个位置的内容都是对应的值:true
  Future 形式读 8 MB:返回 8388608 字节,耗时 1 ms
  异步加锁 ch.lock().get():isValid = true,isShared = false

分步演示

AsynchronousFileChannel
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,macOS,文件在页缓存里
    • 没有验证:真实磁盘的吞吐与延迟、与同步 FileChannel 的对比、Linux 上的实现差异、默认线程池的大小规则、handler 抛异常时的行为;「线程池在做阻塞读」是从线程名推断的(没有读实现)
    京ICP备2026067502号-1京公网安备11010502063487号