1518 字
约 5 分钟
5
Java JUC教程第9章:线程池

Java JUC教程第9章:线程池

章节头部 第9章

🏊‍♂️ 线程池

掌握线程池的设计原理、核心参数配置和性能优化技巧
学习目标

学习目标

  • 理解线程池的设计原理和工作机制
  • 掌握ThreadPoolExecutor的使用和配置
  • 熟悉核心参数的含义和调优方法
  • 了解各种拒绝策略的应用场景
  • 学会线程池的监控和性能调优

线程池原理

线程池原理

线程池(Thread Pool)是一种线程使用模式,它预先创建一定数量的线程,并将这些线程放入池中进行管理。当有任务需要执行时,从池中取出空闲线程来执行任务,任务完成后线程返回池中等待下次使用。

为什么需要线程池

线程的创建和销毁是昂贵的操作,频繁创建销毁线程会消耗大量系统资源。线程池通过复用线程,避免了这种开销,同时提供了更好的线程管理和控制能力。

线程池的优势

提高性能避免频繁创建销毁线程的开销,提高任务执行效率。资源控制限制并发线程数量,防止系统资源耗尽。统一管理提供统一的线程管理和监控机制。

线程池工作原理

  • 任务提交:客户端向线程池提交任务
  • 线程分配:线程池根据策略分配线程执行任务
  • 任务执行:工作线程从任务队列中取出任务并执行
  • 线程回收:任务完成后,线程返回池中等待下次使用
  • 池管理:根据负载情况动态调整线程数量

ThreadPoolExecutor详解

ThreadPoolExecutor详解

ThreadPoolExecutor是Java中最核心的线程池实现,它提供了丰富的配置选项和灵活的扩展机制。理解其构造参数和工作流程是掌握线程池的关键。

构造参数详解

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

corePoolSize核心线程数,即使空闲也会保留在池中的线程数量。maximumPoolSize最大线程数,池中允许的最大线程数量。keepAliveTime空闲线程的存活时间,超过核心线程数的线程在空闲时的最大存活时间。workQueue任务队列,用于存储等待执行的任务。threadFactory线程工厂,用于创建新线程。handler拒绝策略,当任务无法执行时的处理策略。

工作流程

执行流程

步骤1:如果当前线程数 < corePoolSize,创建新线程执行任务步骤2:如果当前线程数 >= corePoolSize,将任务加入工作队列步骤3:如果队列已满且当前线程数 < maximumPoolSize,创建新线程步骤4:如果队列已满且当前线程数 >= maximumPoolSize,执行拒绝策略
核心参数配置

核心参数配置

合理配置线程池参数是保证系统性能的关键。不同的应用场景需要不同的参数配置策略。

参数配置原则

CPU密集型任务

  • corePoolSize = CPU核心数 + 1
  • maximumPoolSize = CPU核心数 + 1
  • 使用SynchronousQueue

IO密集型任务

  • corePoolSize = CPU核心数 * 2
  • maximumPoolSize = CPU核心数 * 2
  • 使用LinkedBlockingQueue

混合型任务

  • 根据任务特性动态调整
  • 监控系统负载进行优化
  • 使用ArrayBlockingQueue

队列选择策略

// 1. SynchronousQueue - 直接提交队列
ExecutorService executor1 = new ThreadPoolExecutor(
    5, 10, 60L, TimeUnit.SECONDS,
    new SynchronousQueue<>());

// 2. LinkedBlockingQueue - 无界队列
ExecutorService executor2 = new ThreadPoolExecutor(
    5, 10, 60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>());

// 3. ArrayBlockingQueue - 有界队列
ExecutorService executor3 = new ThreadPoolExecutor(
    5, 10, 60L, TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(100));

拒绝策略

拒绝策略

当线程池无法处理新提交的任务时,会执行拒绝策略。Java提供了四种内置的拒绝策略,也支持自定义拒绝策略。

内置拒绝策略

AbortPolicy默认策略,直接抛出RejectedExecutionException异常。CallerRunsPolicy由调用线程执行该任务,可以减缓新任务的提交速度。DiscardPolicy静默丢弃无法处理的任务,不抛出异常。DiscardOldestPolicy丢弃队列中最老的任务,然后重新提交当前任务。

自定义拒绝策略

public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 记录日志
        logger.warn("Task {} rejected from {}", r.toString(), executor.toString());
        
        // 尝试放入备用队列
        if (!backupQueue.offer(r)) {
            // 如果备用队列也满了,则执行其他策略
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " + executor.toString());
        }
    }
}

线程池监控

线程池监控与调优

有效的监控是线程池调优的基础。通过监控关键指标,可以及时发现性能问题并进行优化。

关键监控指标

线程数指标

  • 当前线程数:getPoolSize()
  • 活跃线程数:getActiveCount()
  • 最大线程数:getLargestPoolSize()

任务执行指标

  • 已完成任务数:getCompletedTaskCount()
  • 总任务数:getTaskCount()
  • 队列大小:getQueue().size()

性能指标

  • 任务执行时间
  • 任务等待时间
  • 线程利用率

监控实现示例

public class ThreadPoolMonitor {
    private final ThreadPoolExecutor executor;
    private final ScheduledExecutorService monitor;
    
    public ThreadPoolMonitor(ThreadPoolExecutor executor) {
        this.executor = executor;
        this.monitor = Executors.newScheduledThreadPool(1);
        startMonitoring();
    }
    
    private void startMonitoring() {
        monitor.scheduleAtFixedRate(() -> {
            logger.info("ThreadPool Status: " +
                "Pool Size: {}, Active: {}, Completed: {}, Queue Size: {}",
                executor.getPoolSize(),
                executor.getActiveCount(),
                executor.getCompletedTaskCount(),
                executor.getQueue().size());
        }, 0, 30, TimeUnit.SECONDS);
    }
}

调优建议

合理设置核心线程数:根据CPU核心数和任务类型确定选择合适的队列:根据任务特性选择队列类型和大小设置合理的拒绝策略:根据业务需求选择或自定义拒绝策略定期监控和调整:根据监控数据动态调整参数避免无界队列:防止内存溢出
章节导航 上一章:原子类 返回目录 下一章:Executors工具类

Java JUC教程第9章:线程池
https://clxhxhhr.top/posts/3024/
作者
clxstart
发布于
2026-09-24
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。