
在 JDK 源码中,有多处证据表明 Windows 平台上的虚拟线程在 I/O 操作中使用了 IOCP(I/O Completion Port)机制,主要体现在异步 I/O 处理和线程调度的结合上。以下是关键代码片段的分析:
1.IOCP 的初始化与虚拟线程调度的关联Iocp.java 是 Windows 平台上 IOCP 的核心实现类,其内部维护了与系统 IOCP 的交互。虚拟线程在处理异步 I/O 时,依赖于 IOCP 完成端口来接收 I/O 操作的完成通知。
代码片段(Iocp.java):java运行class Iocp extends AsynchronousChannelGroupImpl { private final long port; // IOCP端口句柄 Iocp(AsynchronousChannelProvider provider, ThreadPool pool) throws IOException { super(provider, pool); // 创建IOCP端口 this.port = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, fixedThreadCount()); this.nextCompletionKey = 1; } // 启动处理IOCP事件的线程 Iocp start() { startThreads(new EventHandlerTask()); return this; } }此处通过 createIoCompletionPort 原生方法创建了 IOCP 端口,后续异步 I/O 操作(如文件、网络)会关联到该端口。startThreads(new EventHandlerTask()) 启动线程处理 IOCP 队列中的完成事件,这些线程会驱动虚拟线程的调度(如唤醒等待 I/O 的虚拟线程)。2.虚拟线程与 IOCP 事件的绑定Windows 平台的异步通道(如 WindowsAsynchronousFileChannelImpl)通过 Iocp.associate 方法将通道与 IOCP 端口绑定,并使用虚拟线程处理 I/O 结果。
代码片段(WindowsAsynchronousFileChannelImpl.java):java运行public WindowsAsynchronousFileChannelImpl extends AsynchronousFileChannelImpl implements Iocp.OverlappedChannel, Groupable { private final Iocp iocp; private final int completionKey; WindowsAsynchronousFileChannelImpl(...) throws IOException { // 关联通道到IOCP端口,获取 completionKey this.completionKey = iocp.associate(this, handle); } // 当IOCP事件完成时,通过此方法查找对应的虚拟线程任务 @Override public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) { return ioCache.remove(overlapped); } }通道通过 iocp.associate 绑定到 IOCP 端口,后续 I/O 操作的结果会通过 IOCP 队列通知。getByOverlapped 方法用于将 IOCP 返回的 OVERLAPPED 结构(标识异步操作)映射到对应的虚拟线程任务(PendingFuture),实现 I/O 完成后唤醒虚拟线程。3.IOCP 事件处理驱动虚拟线程调度Iocp.EventHandlerTask 是处理 IOCP 完成事件的核心任务,当 IO 操作完成后,它会从 IOCP 队列中获取结果,并触发虚拟线程的继续执行。
代码片段(Iocp.java):java运行private EventHandlerTask implements Runnable { public void run() { CompletionStatus ioResult = new CompletionStatus(); for (;;) { // 从IOCP队列获取完成事件(阻塞调用,由系统唤醒) getQueuedCompletionStatus(port, ioResult); // 查找事件对应的通道(绑定了虚拟线程任务) OverlappedChannel ch = keyToChannel.get(ioResult.completionKey()); if (ch == null) continue; // 获取虚拟线程的异步任务 PendingFuture<?,?> result = ch.getByOverlapped(ioResult.overlapped()); if (result == null) continue; // 处理结果并唤醒虚拟线程 if (ioResult.error() == 0) { result.setResult(...); // 成功时设置结果 } else { result.setFailure(...); // 失败时设置异常 } Invoker.invoke(result); // 唤醒虚拟线程继续执行 } } }getQueuedCompletionStatus 阻塞等待 IOCP 事件,当有 I/O 操作完成(如读 / 写完成),系统会唤醒该线程。事件处理后,通过 Invoker.invoke(result) 触发虚拟线程从挂起状态恢复执行,实现了虚拟线程与 IOCP 的联动。4.虚拟线程的 I/O 操作依赖 IOCP 的异步机制虚拟线程在执行异步 I/O 时(如文件读写),会通过 JNI 调用将操作提交到 IOCP,自身进入挂起状态,直到 IOCP 返回结果后被唤醒。
代码片段(Iocp.c,JNI 实现):c运行// 向IOCP提交完成通知(用于唤醒等待的线程) JNIEXPORT void JNICALL Java_sun_nio_ch_Iocp_postQueuedCompletionStatus(JNIEnv* env, jclass this, jlong completionPort, jint completionKey) { PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort), 0, (DWORD)completionKey, NULL); } // 从IOCP获取完成事件 JNIEXPORT void JNICALL Java_sun_nio_ch_Iocp_getQueuedCompletionStatus(JNIEnv* env, jclass this, jlong completionPort, jobject obj) { GetQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort), &bytesTransferred, &completionKey, &lpOverlapped, INFINITE); }这些 JNI 方法直接调用 Windows 系统的 IOCP API(PostQueuedCompletionStatus、GetQueuedCompletionStatus),是虚拟线程与 IOCP 交互的底层桥梁。结论Windows 平台上的虚拟线程通过以下方式依赖 IOCP:
异步 I/O 操作(如文件、网络)绑定到 IOCP 端口,由系统内核直接处理 I/O。IOCP 完成事件通过 EventHandlerTask 线程处理,映射到对应的虚拟线程任务。虚拟线程在 I/O 操作期间挂起,待 IOCP 返回结果后被唤醒继续执行,实现高效的非阻塞调度。这些代码片段证明了虚拟线程在 Windows 上的异步 I/O 处理深度依赖 IOCP 机制,以实现低开销的线程调度和高并发性能。