概念定义
平台线程与内核线程一一对应,每条 MB 级栈成本。虚拟线程打破映射:JVM 把它们调度到小规模承载池,阻塞调用时保存栈状态并挂起。每请求一线程的服务器不必再在可读性与规模之间二选一。
工作机制
阻塞操作被运行时拦截:虚拟线程状态入库、承载线程释放、稍后恢复继续执行。钉住(pinning)会破坏这一切——持锁阻塞的 synchronized 块或进入原生栈帧的调用无法卸载,直接冻结承载线程。后续 Java 版本缓解了 synchronized 钉住,原生帧仍是盲区。
使用场景
I/O 密集的请求处理器、扇出聚合器、响应式包装从未覆盖的遗留阻塞库。CPU 密集仍用平台线程池;访问稀缺下游资源改用信号量限流——虚拟线程数量事实上无上限。
常见误区
“阻塞免费”只对合格阻塞成立;“虚拟线程取代一切池”只对 I/O 等待成立。廉价线程诱使无限创建任务,排队问题必须转移去别处。按线程缓存的 thread-local 资源会变成百万级负债。钉住表现为负载下的吞吐断崖:用 JFR 承载钉住事件检测,别靠读代码。
代码示例
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class ScheduledExecutorTasks {
public static void main(String[] args) throws Exception {
AtomicInteger counter = new AtomicInteger(0);
try (ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(2)) {
ScheduledFuture<?> fixedRate = scheduler.scheduleAtFixedRate(() -> {
int count = counter.incrementAndGet();
System.out.println("Fixed-rate task #" + count +
" at " + System.currentTimeMillis() % 10000);
}, 0, 500, TimeUnit.MILLISECONDS);
ScheduledFuture<?> fixedDelay = scheduler.scheduleWithFixedDelay(() -> {
System.out.println("Fixed-delay task at " +
System.currentTimeMillis() % 10000);
}, 100, 1000, TimeUnit.MILLISECONDS);
scheduler.schedule(() -> {
System.out.println("One-shot delayed task");
return null;
}, 2, TimeUnit.SECONDS);
Thread.sleep(3000);
fixedRate.cancel(false);
fixedDelay.cancel(false);
}
System.out.println("Total executions: " + counter.get());
System.out.println("Scheduler shutdown complete");
}
}
import java.util.concurrent.*;
import java.util.List;
public class ThreadPoolExecutor {
public static void main(String[] args) throws InterruptedException {
try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
List<Callable<String>> tasks = List.of(
() -> { Thread.sleep(500); return "Task 1 done"; },
() -> { Thread.sleep(300); return "Task 2 done"; },
() -> { Thread.sleep(700); return "Task 3 done"; },
() -> { Thread.sleep(200); return "Task 4 done"; }
);
List<Future<String>> futures = executor.invokeAll(tasks);
for (Future<String> future : futures) {
try {
System.out.println(future.get());
} catch (ExecutionException e) {
System.err.println("Task failed: " + e.getCause());
}
}
}
System.out.println("All tasks completed");
}
}