一、线程池概述

1.1 什么是线程池

线程池是一种线程管理机制,它维护一组可重用的线程,用于执行提交的任务,避免了频繁创建和销毁线程的开销。

1.2 线程池的优势

  • 降低资源消耗:复用已创建的线程,减少线程创建和销毁的开销

  • 提高响应速度:任务到达时,无需等待线程创建即可立即执行

  • 提高线程可管理性:统一管理、分配和监控线程

  • 防止资源耗尽:通过限制线程数量,避免系统过载

二、ThreadPoolExecutor 核心类

2.1 构造函数参数详解

public ThreadPoolExecutor(
    int corePoolSize,      // 核心线程数
    int maximumPoolSize,   // 最大线程数
    long keepAliveTime,    // 空闲线程存活时间
    TimeUnit unit,         // 时间单位
    BlockingQueue<Runnable> workQueue, // 工作队列
    ThreadFactory threadFactory,       // 线程工厂
    RejectedExecutionHandler handler   // 拒绝策略处理器
)

2.2 各参数详细说明

1. 核心线程数 (corePoolSize)

  • 线程池长期维持的线程数

  • 即使线程空闲也不会被回收(除非设置allowCoreThreadTimeOut)

2. 最大线程数 (maximumPoolSize)

  • 线程池允许创建的最大线程数

  • 当工作队列满时,会创建新线程直到达到此值

3. 空闲线程存活时间 (keepAliveTime)

  • 当线程数大于核心线程数时,多余的空闲线程的存活时间

  • 超过此时间,多余的线程会被终止

4. 工作队列 (workQueue)

  • 用于存放等待执行的任务

  • 常用队列类型:

// 1. 有界队列
new ArrayBlockingQueue<>(capacity);

// 2. 无界队列(慎用,可能导致OOM)
new LinkedBlockingQueue<>();

// 3. 同步移交队列(不存储元素,每个插入必须等待一个移除操作)
new SynchronousQueue<>();

// 4. 优先级队列
new PriorityBlockingQueue<>();

6. 拒绝策略 (RejectedExecutionHandler)
当线程池和工作队列都满时,对新任务的处理策略:

// 1. AbortPolicy(默认):抛出RejectedExecutionException异常
new ThreadPoolExecutor.AbortPolicy();

// 2. CallerRunsPolicy:由调用者线程执行该任务
new ThreadPoolExecutor.CallerRunsPolicy();

// 3. DiscardPolicy:直接丢弃任务,不抛异常
new ThreadPoolExecutor.DiscardPolicy();

// 4. DiscardOldestPolicy:丢弃队列中最旧的任务,然后重新尝试执行
new ThreadPoolExecutor.DiscardOldestPolicy();

// 5. 自定义拒绝策略
RejectedExecutionHandler customHandler = (runnable, executor) -> {
    // 自定义处理逻辑
    System.out.println("Task rejected: " + runnable);
    // 可以记录日志、持久化任务等
};

三、Executors 工厂类

Executors 提供了创建常见线程池的便捷方法:

3.1 常用线程池类型

// 1. 固定大小线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);

// 2. 单线程线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

// 3. 缓存线程池(根据需要创建新线程)
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

// 4. 定时/周期线程池
ScheduledExecutorService scheduledThreadPool = 
    Executors.newScheduledThreadPool(5);

3.2 Executors 的潜在问题

// 可能导致OOM的风险
// 1. newFixedThreadPool 和 newSingleThreadExecutor 使用无界队列
ExecutorService executor = Executors.newFixedThreadPool(10);
// 工作队列是 LinkedBlockingQueue(默认Integer.MAX_VALUE)

// 2. newCachedThreadPool 可能创建过多线程
// 最大线程数是 Integer.MAX_VALUE

四、线程池工作流程

// 线程池执行流程图解
1. 提交任务
   ↓
2. 核心线程是否已满?
   ├─ 否:创建核心线程执行任务
   ↓ 是:
3. 工作队列是否已满?
   ├─ 否:任务加入队列等待
   ↓ 是:
4. 线程数是否达到最大线程数?
   ├─ 否:创建新线程执行任务
   ↓ 是:
5. 执行拒绝策略

五、线程池生命周期管理

5.1 状态转换

RUNNING    → SHUTDOWN    → STOP       → TIDYING    → TERMINATED
(运行中)   (不接受新任务) (不处理任务) (整理状态)   (已终止)
            处理队列任务  中断所有线程

5.2 关闭方法

ExecutorService executor = Executors.newFixedThreadPool(5);

// 1. shutdown(): 平缓关闭
// - 不再接受新任务
// - 已提交的任务会继续执行
// - 不会立即终止
executor.shutdown();

// 2. shutdownNow(): 立即关闭
// - 不再接受新任务
// - 尝试中断正在执行的任务
// - 返回等待执行的任务列表
List<Runnable> notExecutedTasks = executor.shutdownNow();

// 3. awaitTermination(): 等待终止
executor.shutdown();
try {
    if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
        executor.shutdownNow();
    }
} catch (InterruptedException e) {
    executor.shutdownNow();
    Thread.currentThread().interrupt();
}

六、线程池监控

6.1 监控指标

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);

// 获取监控信息
int corePoolSize = executor.getCorePoolSize();       // 核心线程数
int poolSize = executor.getPoolSize();              // 当前线程数
int activeCount = executor.getActiveCount();        // 活动线程数
long completedTaskCount = executor.getCompletedTaskCount(); // 已完成任务数
long taskCount = executor.getTaskCount();           // 总任务数
int queueSize = executor.getQueue().size();         // 队列大小

6.2 扩展 ThreadPoolExecutor 实现监控

public class MonitorThreadPoolExecutor extends ThreadPoolExecutor {
    
    public MonitorThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
                                     long keepAliveTime, TimeUnit unit,
                                     BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }
    
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        System.out.println("准备执行任务: " + r);
        System.out.println("活动线程数: " + getActiveCount());
    }
    
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        System.out.println("任务执行完成: " + r);
        if (t != null) {
            System.out.println("任务执行异常: " + t.getMessage());
        }
    }
    
    @Override
    protected void terminated() {
        super.terminated();
        System.out.println("线程池已终止");
    }
}

七、实际应用示例

7.1 创建自定义线程池

// 创建自定义线程池的最佳实践
public class ThreadPoolManager {
    private static final int CORE_POOL_SIZE = 5;
    private static final int MAX_POOL_SIZE = 20;
    private static final int QUEUE_CAPACITY = 100;
    private static final Long KEEP_ALIVE_TIME = 1L;
    
    public static ThreadPoolExecutor createThreadPool() {
        // 自定义线程工厂
        ThreadFactory threadFactory = new ThreadFactoryBuilder()
            .setNameFormat("custom-pool-%d")
            .setDaemon(false)
            .setPriority(Thread.NORM_PRIORITY)
            .build();
        
        // 自定义拒绝策略
        RejectedExecutionHandler rejectionHandler = (r, executor) -> {
            // 记录日志
            log.warn("Task rejected, queue is full. Task: {}", r);
            // 可以在此处实现任务降级或持久化
            // 例如:保存到数据库,等待后续处理
        };
        
        return new ThreadPoolExecutor(
            CORE_POOL_SIZE,
            MAX_POOL_SIZE,
            KEEP_ALIVE_TIME,
            TimeUnit.MINUTES,
            new ArrayBlockingQueue<>(QUEUE_CAPACITY),
            threadFactory,
            rejectionHandler
        );
    }
}

7.2 定时任务线程池

// 定时任务线程池示例
ScheduledExecutorService scheduledExecutor = 
    Executors.newScheduledThreadPool(3);

// 延迟执行
scheduledExecutor.schedule(() -> {
    System.out.println("延迟5秒执行");
}, 5, TimeUnit.SECONDS);

// 固定频率执行(不受任务执行时间影响)
scheduledExecutor.scheduleAtFixedRate(() -> {
    System.out.println("每3秒执行一次");
}, 1, 3, TimeUnit.SECONDS);

// 固定延迟执行(任务结束后延迟指定时间)
scheduledExecutor.scheduleWithFixedDelay(() -> {
    System.out.println("任务结束延迟2秒后执行");
}, 1, 2, TimeUnit.SECONDS);

7.3 CompletableFuture 结合线程池

// 使用自定义线程池执行 CompletableFuture
ExecutorService customExecutor = Executors.newFixedThreadPool(3);

CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
    System.out.println("任务1在线程: " + Thread.currentThread().getName());
}, customExecutor);

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2在线程: " + Thread.currentThread().getName());
    return "Result";
}, customExecutor);

// 组合多个任务
CompletableFuture<String> combinedFuture = future1.thenCombineAsync(future2, 
    (v1, v2) -> "Combined: " + v2, customExecutor);

combinedFuture.thenAccept(result -> {
    System.out.println("最终结果: " + result);
});

八、最佳实践和注意事项

8.1 线程池参数设置建议

// 1. CPU密集型任务
//   核心线程数 = CPU核心数 + 1
int cpuCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor cpuIntensivePool = new ThreadPoolExecutor(
    cpuCores + 1,
    cpuCores * 2,
    60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(1000)
);

// 2. IO密集型任务
//   核心线程数 = CPU核心数 * 2
ThreadPoolExecutor ioIntensivePool = new ThreadPoolExecutor(
    cpuCores * 2,
    cpuCores * 4,
    60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(1000)
);

// 3. 混合型任务
//   根据业务场景调整,可通过监控动态调整

8.2 常见问题及解决方案

问题1:线程泄漏

// 解决方案:正确关闭线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
try {
    // 执行业务逻辑
    Future<?> future = executor.submit(() -> {
        // 任务逻辑
    });
    future.get(10, TimeUnit.SECONDS); // 设置超时时间
} catch (TimeoutException e) {
    // 处理超时
    future.cancel(true);
} finally {
    // 确保关闭
    executor.shutdown();
}

问题2:任务堆积

// 解决方案:合适的队列大小和拒绝策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5, 10, 60L, TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(100), // 使用有界队列
    new ThreadPoolExecutor.CallerRunsPolicy() // 调用者执行策略
);

// 监控队列大小
if (executor.getQueue().size() > 80) {
    log.warn("线程池队列已使用80%,当前大小: {}", executor.getQueue().size());
    // 触发告警或动态调整
}

问题3:线程池死锁

// 避免场景:任务间相互等待
ExecutorService executor = Executors.newFixedThreadPool(2);

Future<?> future1 = executor.submit(() -> {
    Future<?> innerFuture = executor.submit(() -> {
        System.out.println("内部任务");
    });
    try {
        innerFuture.get(); // 可能导致死锁
    } catch (Exception e) {
        e.printStackTrace();
    }
});

九、Spring中的线程池

9.1 Spring线程池配置

@Configuration
@EnableAsync
public class ThreadPoolConfig {
    
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(5);
        // 最大线程数
        executor.setMaxPoolSize(10);
        // 队列容量
        executor.setQueueCapacity(100);
        // 线程名称前缀
        executor.setThreadNamePrefix("async-thread-");
        // 拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 等待时间
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }
}

9.2 使用 @Async 注解

@Service
public class UserService {
    
    @Async("taskExecutor")
    public CompletableFuture<User> getUserAsync(Long userId) {
        // 异步执行逻辑
        User user = userRepository.findById(userId);
        return CompletableFuture.completedFuture(user);
    }
}

十、总结

线程池选择指南

场景 推荐线程池 说明
CPU密集型 FixedThreadPool 固定线程数,避免上下文切换
IO密集型 CachedThreadPool 弹性线程池,适应IO等待
定时任务 ScheduledThreadPool 支持定时和周期性任务
单线程顺序执行 SingleThreadExecutor 保证任务顺序执行
混合型任务 自定义ThreadPoolExecutor 根据业务特点调整参数

关键要点

  1. 避免使用无界队列,防止OOM

  2. 合理设置线程数,根据任务类型调整

  3. 实现合适的拒绝策略,保证系统稳定性

  4. 及时关闭线程池,释放资源

  5. 监控线程池状态,及时发现和解决问题

线程池调优建议

  1. 通过监控确定最佳参数

  2. 考虑使用动态线程池(根据负载自动调整)

  3. 针对不同业务使用不同的线程池

  4. 考虑使用线程池隔离,避免相互影响

        线程池是Java并发编程的重要工具,正确使用可以显著提升系统性能和稳定性。在实际应用中,应根据具体业务场景选择合适的线程池类型和参数配置。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐