← 中文资源

简体中文版本

虚拟线程

虚拟线程是 JVM 用户态线程,调度到承载线程池上,阻塞即卸载挂起,让“每请求一线程”的同步代码扩展到百万级任务。

阅读英文原文

概念定义

平台线程与内核线程一一对应,每条 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");
    }
}