0Pricing
Java Academy · 课时

ExecutorService 与线程池类型

创建固定、缓存、单线程和定时线程池,并理解各自的适用场景

ExecutorService 与线程池类型 是 CoddyKit 上的免费 Java Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

为什么使用线程池

为每个任务创建新的 Thread 的开销很大——线程的创建和销毁都会产生额外开销。线程池会重复使用一组固定的线程来执行多个任务,从而减少开销并控制资源消耗。

import java.util.concurrent.*;

// Bad practice: new thread per task
new Thread(() -> System.out.println("task")).start();

// Better: reuse threads from a pool
ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> System.out.println("task from pool"));
pool.shutdown();

newFixedThreadPool

创建一个恰好包含 N 个线程的线程池。额外任务会排队,直到有线程可用。当您知道所需的并行度时,这种线程池很适用。

ExecutorService pool = Executors.newFixedThreadPool(4);

for (int i = 0; i < 10; i++) {
    final int taskId = i;
    pool.submit(() -> {
        System.out.println("Task " + taskId + " on " + Thread.currentThread().getName());
    });
}

pool.shutdown();
pool.awaitTermination(10, TimeUnit.SECONDS);

newCachedThreadPool

按需创建线程并重复使用空闲线程。空闲 60 秒的线程会被终止。它适合大量短时任务;但对于长时间运行或数量不受限制的任务存在风险,因为可能耗尽内存。

ExecutorService cached = Executors.newCachedThreadPool();

for (int i = 0; i < 100; i++) {
    cached.submit(() -> {
        // quick task
        double result = Math.sqrt(Math.random());
    });
}
cached.shutdown();

newSingleThreadExecutor

一个恰好包含一个线程的线程池。任务按照提交顺序依次执行。它适合将对共享资源的访问串行化。

ExecutorService single = Executors.newSingleThreadExecutor();

single.submit(() -> System.out.println("Task 1"));
single.submit(() -> System.out.println("Task 2"));
single.submit(() -> System.out.println("Task 3"));
// Always prints: Task 1, Task 2, Task 3 (sequential)
single.shutdown();

newScheduledThreadPool

支持定时任务和重复任务。可用于轮询、重试和后台维护。

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

// One-shot delay
scheduler.schedule(() -> System.out.println("Delayed!"),
    3, TimeUnit.SECONDS);

// Fixed rate (every 2 seconds)
scheduler.scheduleAtFixedRate(
    () -> System.out.println("Tick"),
    0, 2, TimeUnit.SECONDS);

// Run later: scheduler.shutdown();

VirtualThreadExecutor(Java 21 及更高版本)

Java 21 引入了虚拟线程——它们轻量且创建成本低。对于 I/O 密集型工作负载,请使用 Executors.newVirtualThreadPerTaskExecutor():

// Java 21+
try (var exec = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10_000; i++) {
        final int id = i;
        exec.submit(() -> {
            Thread.sleep(100); // blocks without tying up OS thread
            System.out.println("vthread " + id);
        });
    }
} // auto-shutdown

选择合适的线程池

指导原则:

  • CPU 密集型任务:使用固定线程池,N = CPU 核心数
  • 输入/输出密集型任务:使用缓存线程池或虚拟线程
  • 顺序任务:使用单线程执行器
  • 定时/重复任务:使用定时线程池
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService cpuPool = Executors.newFixedThreadPool(cores);
System.out.println("Pool size: " + cores);

自定义 ThreadPoolExecutor

如果需要精细控制,请直接创建 ThreadPoolExecutor:

ThreadPoolExecutor tpe = new ThreadPoolExecutor(
    2,           // corePoolSize
    10,          // maximumPoolSize
    60L,         // keepAliveTime
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100), // work queue
    Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.CallerRunsPolicy() // rejection policy
);
tpe.submit(() -> System.out.println("Custom pool task"));
tpe.shutdown();

优雅关闭

务必关闭 ExecutorService 以释放线程。shutdown() 会停止接受新任务,但会完成队列中的任务。shutdownNow() 会尝试取消正在运行的任务。

ExecutorService pool = Executors.newFixedThreadPool(4);
// ... submit tasks ...

pool.shutdown(); // no new tasks
try {
    if (!pool.awaitTermination(30, TimeUnit.SECONDS)) {
        pool.shutdownNow(); // force cancel
    }
} catch (InterruptedException e) {
    pool.shutdownNow();
    Thread.currentThread().interrupt();
}

ExecutorService 作为 AutoCloseable(Java 19 及更高版本)

在 Java 19 及更高版本中,ExecutorService 实现了 AutoCloseable。请使用带资源的 try 语句自动关闭:

// Java 19+ (preview), Java 21 stable
try (ExecutorService pool = Executors.newFixedThreadPool(4)) {
    pool.submit(() -> System.out.println("task"));
} // pool.close() called: waits for tasks then shuts down

拒绝策略

当线程池达到容量上限(所有线程都在工作且队列已满)时,拒绝策略会处理溢出的任务:

  • AbortPolicy(默认):抛出 RejectedExecutionException
  • CallerRunsPolicy:由调用线程执行任务
  • DiscardPolicy:静默丢弃任务
  • DiscardOldestPolicy:丢弃队列中最早的任务

快速检查

您有一个执行大量计算的 CPU 密集型任务。固定线程池应包含多少个线程?

回顾:ExecutorService 与线程池

要点:

  • 固定线程池:固定数量的 N 个线程;额外任务排队
  • 缓存线程池:按需扩展;空闲线程在 60 秒后过期
  • 单线程:保证串行执行顺序
  • 定时线程池:延迟任务和重复任务
  • 务必调用 shutdown();使用 awaitTermination() 实现干净退出

常见问题解答

「ExecutorService 与线程池类型」课时是免费的吗?

是的 — 「ExecutorService 与线程池类型」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「ExecutorService 与线程池类型」这节课中我会学到什么?

创建固定、缓存、单线程和定时线程池,并理解各自的适用场景 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「ExecutorService 与线程池类型」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. ExecutorService 与线程池类型
  2. 提交任务:Runnable 与 Callable
  3. Future 与错误处理
  4. 使用 ScheduledExecutorService 执行重复任务
← 返回 Java Academy