Skip to content

线程池有哪几种,怎么使用

线程池概述

  • 定义
  • 线程池(Thread Pool)是一种管理线程的机制,通过维护一组预创建的线程来执行任务,避免频繁创建和销毁线程的开销,提高性能和资源利用率。
  • Java 中线程池由 java.util.concurrent 包的 Executor 框架提供,主要通过 ThreadPoolExecutorExecutors 工厂类实现。
  • 核心作用
  • 性能优化:复用线程,减少创建/销毁开销。
  • 资源控制:限制线程数量,避免系统过载。
  • 任务管理:支持任务队列、拒绝策略、异步执行。
  • 核心点
  • Java 提供多种线程池类型(如固定大小、缓存、单线程、定时任务),通过 Executors 创建,适用于不同场景。

1. Java 线程池的类型

Java 通过 Executors 工厂类提供以下几种常用线程池,每种适合特定场景:

(1) FixedThreadPool(固定大小线程池)

  • 特点
  • 固定数量的线程(nThreads),任务队列无界(LinkedBlockingQueue)。
  • 线程数不变,适合长期运行的任务。
  • 适用场景
  • 任务量稳定,需要控制并发线程数(如 Web 服务器)。
  • 创建java ExecutorService executor = Executors.newFixedThreadPool(4); // 4 个线程
  • 注意
  • 无界队列可能导致内存溢出(OOM),任务过多时需谨慎。

(2) CachedThreadPool(缓存线程池)

  • 特点
  • 线程数动态调整(0 到 Integer.MAX_VALUE),空闲线程存活 60 秒。
  • 使用 SynchronousQueue,任务直接交给线程,无队列存储。
  • 适用场景
  • 短时突发任务,任务执行时间短(如轻量级异步任务)。
  • 创建java ExecutorService executor = Executors.newCachedThreadPool();
  • 注意
  • 线程数可能无限制增长,高并发下可能耗尽资源。

(3) SingleThreadExecutor(单线程池)

  • 特点
  • 只有一个线程,按顺序执行任务,队列无界(LinkedBlockingQueue)。
  • 保证任务串行执行。
  • 适用场景
  • 需要严格顺序执行的任务(如日志写入、单线程事件处理)。
  • 创建java ExecutorService executor = Executors.newSingleThreadExecutor();
  • 注意
  • 单线程性能有限,任务积压可能导致延迟。

(4) ScheduledThreadPool(定时任务线程池)

  • 特点
  • 支持定时和周期性任务执行,基于 DelayedWorkQueue
  • 线程数固定或动态,适合调度任务。
  • 适用场景
  • 定时任务、周期任务(如心跳检测、定时清理)。
  • 创建java ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); // 2 个线程
  • 方法
  • schedule(Runnable, delay, TimeUnit):延迟执行。
  • scheduleAtFixedRate(Runnable, initialDelay, period, TimeUnit):固定频率。
  • scheduleWithFixedDelay(Runnable, initialDelay, delay, TimeUnit):固定间隔。
  • 示例java executor.schedule(() -> System.out.println("Task"), 1, TimeUnit.SECONDS); // 1秒后执行 executor.scheduleAtFixedRate(() -> System.out.println("Periodic"), 0, 2, TimeUnit.SECONDS); // 每2秒执行

(5) WorkStealingPool(工作窃取线程池,Java 8+)

  • 特点
  • 基于 Fork/Join 框架(ForkJoinPool),每个线程有自己的任务队列,空闲线程可“窃取”其他线程的任务。
  • 线程数默认等于 CPU 核心数。
  • 适用场景
  • 递归、分治任务(如并行计算、树形处理)。
  • 创建java ExecutorService executor = Executors.newWorkStealingPool();
  • 注意
  • 适合任务分解,不适合 I/O 密集型任务。

(6) Custom ThreadPoolExecutor(自定义线程池)

  • 特点
  • 通过 ThreadPoolExecutor 手动配置线程池参数:
    • corePoolSize:核心线程数。
    • maximumPoolSize:最大线程数。
    • keepAliveTime:空闲线程存活时间。
    • workQueue:任务队列(如 LinkedBlockingQueueArrayBlockingQueue)。
    • threadFactory:线程创建工厂。
    • handler:拒绝策略(如 AbortPolicyCallerRunsPolicy)。
  • 适用场景
  • 需精确控制线程池行为(如限制队列大小、自定义拒绝策略)。
  • 创建java ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, // corePoolSize 4, // maximumPoolSize 60, TimeUnit.SECONDS, // keepAliveTime new LinkedBlockingQueue<>(100), // workQueue Executors.defaultThreadFactory(), // threadFactory new ThreadPoolExecutor.AbortPolicy() // rejectedExecutionHandler );

2. 线程池的使用方法

以下是通过 Java 线程池执行任务的通用步骤和代码示例:

(1) 创建线程池

  • 使用 Executors 工厂方法或 ThreadPoolExecutor 创建。
ExecutorService executor = Executors.newFixedThreadPool(4);

(2) 提交任务

  • 方式
  • execute(Runnable):执行无返回值的任务。
  • submit(Runnable/Callable):执行有返回值的任务,返回 Future
  • 示例: ```java // 无返回值 executor.execute(() -> System.out.println("Task executed"));

// 有返回值 Future future = executor.submit(() -> "Result"); try { String result = future.get(); // 阻塞获取结果 System.out.println(result); } catch (Exception e) { e.printStackTrace(); } ```

(3) 管理任务

  • 批量提交java List<Callable<String>> tasks = Arrays.asList( () -> "Task 1", () -> "Task 2" ); List<Future<String>> futures = executor.invokeAll(tasks); futures.forEach(f -> { try { System.out.println(f.get()); } catch (Exception e) { e.printStackTrace(); } });
  • 定时任务ScheduledExecutorService): java ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.scheduleAtFixedRate(() -> System.out.println("Periodic task"), 0, 1, TimeUnit.SECONDS);

(4) 关闭线程池

  • 方式
  • shutdown():停止接受新任务,等待现有任务完成。
  • shutdownNow():立即停止,尝试中断运行任务,返回未执行任务。
  • awaitTermination(timeout, unit):等待关闭完成。
  • 示例java executor.shutdown(); try { if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); } } catch (InterruptedException e) { executor.shutdownNow(); }

(5) 完整示例

import java.util.concurrent.*;

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 提交任务
        for (int i = 0; i < 5; i++) {
            int taskId = i;
            executor.submit(() -> {
                System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        // 关闭线程池
        executor.shutdown();
        try {
            executor.awaitTermination(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
    }
}

输出(示例):

Task 0 executed by pool-1-thread-1
Task 1 executed by pool-1-thread-2
Task 2 executed by pool-1-thread-1
Task 3 executed by pool-1-thread-2
Task 4 executed by pool-1-thread-1

3. 线程池参数与配置

ThreadPoolExecutor 的核心参数影响线程池行为:

  • corePoolSize
  • 常驻线程数,即使空闲也保留。
  • maximumPoolSize
  • 最大允许线程数,队列满时创建。
  • keepAliveTime
  • 非核心线程空闲存活时间。
  • workQueue
  • 任务队列类型:
    • LinkedBlockingQueue:无界队列。
    • ArrayBlockingQueue:有界队列。
    • SynchronousQueue:无缓冲队列。
    • PriorityBlockingQueue:优先级队列。
  • threadFactory
  • 自定义线程名称、优先级等。
  • 示例: java ThreadFactory factory = r -> new Thread(r, "my-thread-" + r.hashCode());
  • rejectedExecutionHandler
  • 队列满且线程满时的拒绝策略:
    • AbortPolicy:抛 RejectedExecutionException(默认)。
    • CallerRunsPolicy:调用者线程执行。
    • DiscardPolicy:丢弃任务。
    • DiscardOldestPolicy:丢弃最旧任务。
  • 示例: java ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 4, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy() );

4. 使用场景

  • FixedThreadPool
  • Web 服务器处理请求,控制并发。
  • CachedThreadPool
  • 短时任务(如异步日志、事件处理)。
  • SingleThreadExecutor
  • 顺序任务(如数据库事务日志)。
  • ScheduledThreadPool
  • 定时任务(如监控、清理)。
  • WorkStealingPool
  • 并行计算(如 Fork/Join 任务)。
  • Custom ThreadPoolExecutor
  • 高并发系统,需精确控制队列和拒绝策略(如电商秒杀)。

5. 注意事项

  • 线程池大小
  • CPU 密集型:核心数 + 1(如计算任务)。
  • I/O 密集型:2 × 核心数 或更高(如网络请求)。
  • 示例:4 核 CPU,计算任务用 5 线程,I/O 任务用 8-10 线程。
  • 队列选择
  • 无界队列(LinkedBlockingQueue):小心 OOM。
  • 有界队列(ArrayBlockingQueue):需配拒绝策略。
  • 拒绝策略
  • 选择适合业务的策略,如 CallerRunsPolicy 降低速率,AbortPolicy 抛异常。
  • 关闭管理
  • 总是调用 shutdownshutdownNow,避免资源泄漏。
  • 异常处理
  • execute 不捕获异常,需在 Runnable 内处理。
  • submit 返回 Future,通过 get 捕获异常。
  • 线程安全
  • 线程池本身线程安全,但任务逻辑需确保安全(如共享资源加锁)。
  • 避免误用
  • 不要用 CachedThreadPool 处理长时任务,可能耗尽资源。
  • 避免无界队列无限积压任务。

6. 面试角度

  • 问“Java 线程池有哪些”
  • 提 FixedThreadPool、CachedThreadPool、SingleThreadExecutor、ScheduledThreadPool、WorkStealingPool、ThreadPoolExecutor。
  • 问“如何使用线程池”
  • 提创建(Executors)、提交(execute/submit)、关闭(shutdown),给代码示例。
  • 问“线程池参数”
  • 提 corePoolSize、maximumPoolSize、workQueue、rejectedExecutionHandler,说明作用。
  • 问“场景选择”
  • 提 FixedThreadPool(稳定并发)、CachedThreadPool(短任务)、ScheduledThreadPool(定时)。
  • 问“注意事项”
  • 提线程大小、队列 OOM、拒绝策略、异常处理、关闭。
  • 问“自定义线程池”
  • ThreadPoolExecutor 配置,举有界队列 + 拒绝策略示例。

7. 总结

  • 线程池类型
  • FixedThreadPool(固定线程)、CachedThreadPool(动态线程)、SingleThreadExecutor(单线程)、ScheduledThreadPool(定时)、WorkStealingPool(Fork/Join)、ThreadPoolExecutor(自定义)。
  • 使用方法
  • 创建(ExecutorsThreadPoolExecutor)、提交(execute/submit)、管理(FutureinvokeAll)、关闭(shutdown)。
  • 场景
  • 并发控制(Fixed)、短任务(Cached)、顺序(Single)、定时(Scheduled)、并行(WorkStealing)。
  • 注意
  • 配置线程数/队列、处理异常、选择拒绝策略、正确关闭。
  • 面试建议
  • 提类型、代码示例(submit + shutdown)、参数配置(corePoolSize 等)、场景(Web vs 定时)、注意事项(OOM、异常),清晰展示理解。

If you want to dive deeper into any part (e.g., ThreadPoolExecutor source code, rejection policies, or thread pool tuning for specific workloads), let me know, and I can further refine the answer!