代码对比
✕ Java 8
ExecutorService pool =
Executors.newFixedThreadPool(10);
List<Future<String>> futures =
urls.stream()
.map(u -> pool.submit(
() -> fetchUrl(u)))
.toList();
// manual shutdown, blocking get()
✓ Java 21+
try (var exec = Executors
.newVirtualThreadPerTaskExecutor()) {
var results = urls.stream()
.map(u -> exec.submit(
() -> client.send(req(u),
ofString()).body()))
.toList().stream()
.map(Future::join).toList();
}
发现此代码有问题? 告诉我们。
为什么现代方式更好
每个请求一个线程
无需调整池大小——每个 URL 一个虚拟线程。
简单的错误处理
每个任务在自己的线程中处理错误。
简洁代码
现代 HttpClient 与虚拟线程的语义清晰。
旧方式
线程池 + URLConnection
现代方式
虚拟线程 + HttpClient
自 JDK
21
难度
中级
JDK 支持
使用虚拟线程进行并发 HTTP 请求
可用
自 JDK 21 LTS 起广泛可用(2023 年 9 月)
工作原理
虚拟线程使每个 HTTP 请求使用一个线程变得切实可行。每个虚拟线程在等待 I/O 时会挂载,不会阻塞平台线程。
相关文档