Java线程池从入门到精通:框架自带 vs 自定义,我该怎么选?

29 阅读23分钟

前言

在Java后端开发中,线程池是一个绕不开的话题。不管你是做Web开发、微服务,还是处理异步任务,都离不开它。但很多小伙伴在使用线程池时都会有这样的困惑:

"框架自带线程池挺好用的,为什么还要自定义?" "什么情况下必须自定义线程池?" "自定义线程池该怎么配置参数?"

今天这篇文章,我将从源码层面深入剖析Java线程池的原理,对比分析框架自带线程池自定义线程池的区别,并通过大量实战代码帮你彻底搞懂这个知识点。


一、线程池到底是什么?

1.1 为什么需要线程池?

在正式介绍线程池之前,我们先来理解一个问题:为什么需要线程池?

假设这样一个场景:我们要处理1000个请求,每个请求需要执行一个耗时的IO操作。

不用线程池的写法:

public class BadExample {
    
    public void processRequests(List<Request> requests) {
        for (Request request : requests) {
            // 每来一个请求就创建一个线程
            new Thread(() -> {
                // 处理IO操作
                doIOOperation(request);
            }).start();
        }
    }
}

这种写法会有什么问题?

问题说明
线程创建销毁开销大每次请求都创建新线程,1000个请求就要创建1000个线程,线程创建和销毁需要调用系统内核,非常耗时
内存占用高每个线程默认占用1MB左右的栈空间,1000个线程就占用1GB内存
系统资源耗尽线程数量不可控,可能创建数万线程,导致OOM(OutOfMemoryError)
无法复用任务执行完线程就销毁,无法复用,资源浪费严重

用线程池的写法:

public class GoodExample {
    
    private ExecutorService executor = Executors.newFixedThreadPool(10);
    
    public void processRequests(List<Request> requests) {
        for (Request request : requests) {
            // 提交任务到线程池,线程会被复用
            executor.execute(() -> {
                doIOOperation(request);
            });
        }
    }
}

线程池就像一个任务加工厂

  • 核心工人数量固定(比如10个)
  • 有任务就处理,没任务就待命
  • 工人可以复用,不会每来一个任务就换人
  • 任务太多时,有等候区排队
  • 超过负荷可以扩容或者拒绝任务

1.2 线程池的核心概念

在Java中,线程池由以下核心组件构成:

┌─────────────────────────────────────────────────────────┐
│                      线程池                              │
│  ┌─────────────────────────────────────────────────┐    │
│  │                  任务队列                        │    │
│  │   [任务1] [任务2] [任务3] [任务4] ......         │    │
│  └─────────────────────────────────────────────────┘    │
│                        ↓↑                               │
│  ┌─────────────────────────────────────────────────┐    │
│  │           线程池核心参数                         │    │
│  │   • corePoolSize(核心线程数)                  │    │
│  │   • maximumPoolSize(最大线程数)               │    │
│  │   • keepAliveTime(空闲线程存活时间)           │    │
│  │   • unit(时间单位)                            │    │
│  │   • workQueue(任务队列)                       │    │
│  │   • threadFactory(线程工厂)                   │    │
│  │   • handler(拒绝策略)                         │    │
│  └─────────────────────────────────────────────────┘    │
│                        ↓↑                               │
│  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐              │
│  │线程1 │  │线程2 │  │线程3 │  │线程4 │  ...          │
│  └──────┘  └──────┘  └──────┘  └──────┘              │
└─────────────────────────────────────────────────────────┘

核心参数解析:

参数含义类比理解
corePoolSize核心线程数,线程池始终保持的线程数量正式员工数量
maximumPoolSize最大线程数,线程池允许的最大线程数量公司最大员工数(含外包)
keepAliveTime空闲线程存活时间临时工没活干多久被辞退
workQueue任务队列,用于存放待执行的任务任务等候区
threadFactory线程工厂,用于创建新线程人事部门
handler拒绝策略,当任务无法执行时的处理方式任务太多时的应对方案

1.3 线程池的工作流程

线程池的任务处理流程可以用一张图来描述:

                    ┌─────────────────┐
                       有新任务提交   
                    └────────┬────────┘
                             
                             
                    ┌─────────────────┐
                      核心线程数未满? 
                    └────────┬────────┘
                             
              ┌──────────────┴──────────────┐
               Yes                          No
                                           
    ┌─────────────────┐             ┌─────────────────┐
     创建新核心线程                队列已满?       
     执行新任务                  └────────┬────────┘
    └─────────────────┘                      
                                    ┌─────────┴─────────┐
                                     Yes                No
                                                       
                          ┌─────────────────┐  ┌─────────────────┐
                           最大线程数未满?    进入队列等待    
                          └────────┬────────┘  └─────────────────┘
                                   
                        ┌──────────┴──────────┐
                         Yes                  No
                                             
              ┌─────────────────┐    ┌─────────────────┐
               创建临时线程         执行拒绝策略    
               执行新任务          (抛异常/丢弃等)│
              └─────────────────┘    └─────────────────┘

简化版规则:

  1. 先 core 满不满:任务来了,先看核心线程有没有空
  2. 再队列满不满:核心线程满了,看队列能不能排队
  3. 最后 max 满不满:队列也满了,看能不能扩容到最大线程数
  4. 都不行就拒绝:都满了,只能执行拒绝策略

二、Java原生线程池:Executor框架

2.1 家族图谱一览

Java的线程池体系非常完善,主要分为以下几类:

java.util.concurrent.Executor(接口)
        │
        ├── ExecutorService(接口)
        │       │
        │       ├── AbstractExecutorService(抽象类)
        │       │       │
        │       │       └── ThreadPoolExecutor(核心实现)
        │       │               │
        │       │               └── ScheduledThreadPoolExecutor(定时任务)
        │       │
        │       └── Executors(工具类,工厂方法)
        │               │
        │               ├── newFixedThreadPool()  → 固定大小线程池
        │               ├── newCachedThreadPool() → 缓存线程池
        │               ├── newSingleThreadExecutor() → 单线程线程池
        │               └── newScheduledThreadPool() → 定时线程池
        │
        └── Executors(工具类)

2.2 四种常用线程池详解

2.2.1 FixedThreadPool(固定大小线程池)

创建方式:

// 创建一个固定5个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(5);

// 或者使用ThreadPoolExecutor直接创建
ExecutorService executor = new ThreadPoolExecutor(
    5,      // corePoolSize = 5
    5,      // maximumPoolSize = 5(与核心线程数相同)
    0L,     // keepAliveTime = 0(不需要,因为没有临时线程)
    TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>()  // 无界队列
);

特点:

  • 核心线程数 = 最大线程数,不会创建临时线程
  • 使用无界队列(Integer.MAX_VALUE),理论上可以无限接收任务
  • 适合CPU密集型任务,或者任务量已知、相对平稳的场景

执行流程图示:

                    ┌─────────────────┐
                    │   新任务        │
                    └────────┬────────┘
                             │
                             ▼
              ┌───────────────────────────────┐
              │  核心线程1 | 2 | 3 | 4 | 5     │
              │  [忙] [忙] [忙] [忙] [忙]      │
              │                               │
              │     [全部忙碌,继续入队]        │
              └───────────────────────────────┘
                             │
                             ▼
                    ┌─────────────────┐
                    │   无界队列       │
                    │ [任务6][任务7][任务8]...│
                    └─────────────────┘

实战示例:

public class FixedThreadPoolDemo {
    
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        for (int i = 1; i <= 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName + " 正在执行任务 " + taskId);
                
                try {
                    // 模拟任务执行
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println(threadName + " 完成任务 " + taskId);
            });
        }
        
        // 关闭线程池
        executor.shutdown();
    }
}

输出示例:

pool-1-thread-1 正在执行任务 1
pool-1-thread-2 正在执行任务 2
pool-1-thread-3 正在执行任务 3
pool-1-thread-1 完成任务 1
pool-1-thread-1 正在执行任务 4
pool-1-thread-2 完成任务 2
pool-1-thread-2 正在执行任务 5
...

可以看到,3个线程交替执行10个任务,复用线程,无需反复创建销毁。

2.2.2 CachedThreadPool(缓存线程池)

创建方式:

// 创建缓存线程池
ExecutorService executor = Executors.newCachedThreadPool();

// 等价于
new ThreadPoolExecutor(
    0,                          // corePoolSize = 0
    Integer.MAX_VALUE,          // maximumPoolSize = 无穷大
    60L,                        // keepAliveTime = 60秒
    TimeUnit.SECONDS,
    new SynchronousQueue<Runnable>()  // 同步队列
);

特点:

  • 核心线程数为0,所有线程都是临时线程
  • 最大线程数无上限(理论上)
  • 60秒内没有任务执行的线程会被销毁
  • 使用SynchronousQueue同步队列,不存储任务
  • 适合短时间大量小任务的场景

执行流程图示:

                    ┌─────────────────┐
                       新任务        
                    └────────┬────────┘
                             
                             
              ┌───────────────────────────────┐
                SynchronousQueue             
                [必须有消费者立即消费]        
              └───────────────────────────────┘
                             
                             
              ┌───────────────────────────────┐
               有空闲线程?                   
              └───────────────┬───────────────┘
                              
                 ┌────────────┴────────────┐
                  Yes                       No
                                           
        ┌─────────────────┐        ┌─────────────────┐
         复用空闲线程             创建新线程      
         执行任务                执行任务       
        └─────────────────┘        └─────────────────┘

实战示例:

public class CachedThreadPoolDemo {
    
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        
        long startTime = System.currentTimeMillis();
        
        for (int i = 1; i <= 20; i++) {
            final int taskId = i;
            executor.execute(() -> {
                String threadName = Thread.currentThread().getName();
                System.out.println("任务 " + taskId + " -> " + threadName);
                
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        
        executor.shutdown();
        
        try {
            // 等待所有任务完成
            executor.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        long endTime = System.currentTimeMillis();
        System.out.println("总耗时:" + (endTime - startTime) + "ms");
    }
}

危险提示: CachedThreadPool在任务量大时可能创建过多线程,导致OOM!

// 危险代码示例:模拟OOM
public class OOMDemo {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        
        // 模拟无限提交任务
        IntStream.range(0, Integer.MAX_VALUE).forEach(i -> {
            executor.execute(() -> {
                try {
                    Thread.sleep(Integer.MAX_VALUE);
                } catch (InterruptedException e) {}
            });
        });
    }
}

2.2.3 SingleThreadExecutor(单线程线程池)

创建方式:

ExecutorService executor = Executors.newSingleThreadExecutor();

// 等价于
new ThreadPoolExecutor(
    1,      // corePoolSize = 1
    1,      // maximumPoolSize = 1
    0L,     // keepAliveTime = 0
    TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>()  // 无界队列
);

特点:

  • 只有一个工作线程
  • 所有任务串行执行
  • 任务队列无界
  • 保证任务执行顺序,不会出现并发问题
  • 适合需要保证顺序执行的场景

实战示例:

public class SingleThreadExecutorDemo {
    
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        
        for (int i = 1; i <= 5; i++) {
            final int taskId = i;
            executor.execute(() -> {
                System.out.println("任务 " + taskId + " 开始,线程:" 
                    + Thread.currentThread().getName());
                
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                System.out.println("任务 " + taskId + " 结束");
            });
        }
        
        executor.shutdown();
    }
}

输出:

任务 1 开始,线程:pool-1-thread-1
任务 1 结束
任务 2 开始,线程:pool-1-thread-1
任务 2 结束
任务 3 开始,线程:pool-1-thread-1
...

2.2.4 ScheduledThreadPool(定时线程池)

创建方式:

ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);

// 等价于
new ScheduledThreadPoolExecutor(5);

特点:

  • 支持定时任务周期任务
  • 适合需要延迟执行定期执行的场景
  • 底层使用DelayedWorkQueue

核心方法:

ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);

// 1. 延迟执行(只执行一次)
executor.schedule(() -> {
    System.out.println("延迟3秒后执行");
}, 3, TimeUnit.SECONDS);

// 2. 固定频率执行(从上一定期任务开始时间计算)
executor.scheduleAtFixedRate(() -> {
    System.out.println("每2秒执行一次(固定频率)");
}, 0, 2, TimeUnit.SECONDS);

// 3. 固定延迟执行(从上一次任务完成时间计算)
executor.scheduleWithFixedDelay(() -> {
    System.out.println("每2秒执行一次(固定延迟)");
}, 0, 2, TimeUnit.SECONDS);

scheduleAtFixedRate vs scheduleWithFixedDelay 对比:

假设任务执行需要3秒,周期设置为2秒:

scheduleAtFixedRate(固定频率):
  |---任务1(3s)---|---任务2(3s)---|---任务3(3s)---|
  0s              2s              4s              6s
  ⚠️ 任务会在2秒间隔后立即开始,不等待上一个任务完成!

scheduleWithFixedDelay(固定延迟):
  |---任务1(3s)---|---任务2(3s)---|---任务3(3s)---|
  0s              5s              10s             15s
  ✅ 任务会在上一个任务完成后,等待2秒再开始

2.3 线程池参数配置最佳实践

阿里巴巴Java开发手册明确指出:禁止使用Executors创建线程池,应该使用ThreadPoolExecutor手动创建。

// ❌ 不推荐:使用Executors创建(阿里巴巴规范)
ExecutorService executor = Executors.newFixedThreadPool(10);

// ✅ 推荐:使用ThreadPoolExecutor手动创建
ExecutorService executor = new ThreadPoolExecutor(
    10,                                     // corePoolSize
    20,                                     // maximumPoolSize
    60L,                                    // keepAliveTime
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(200),         // 有界队列
    new ThreadFactory() {                   // 自定义线程工厂
        private int count = 0;
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r);
            thread.setName("my-pool-thread-" + count++);
            return thread;
        }
    },
    new ThreadPoolExecutor.AbortPolicy()    // 拒绝策略
);

为什么阿里巴巴要禁止Executors?

Executors创建方式问题风险
newFixedThreadPool使用无界队列,可能堆积大量任务OOM
newCachedThreadPool最大线程数无限制,可能创建过多线程OOM
newSingleThreadExecutor使用无界队列,可能堆积大量任务OOM
newScheduledThreadPool最大线程数无限制OOM

三、ThreadPoolExecutor 源码解析

3.1 核心属性解读

ThreadPoolExecutor是Java线程池的核心实现,让我们深入源码看看:

public class ThreadPoolExecutor extends AbstractExecutorService {
    
    // 原子变量:控制线程池状态和当前工作线程数
    // 高3位表示状态,低29位表示线程数
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    
    // 线程池的5种状态
    private static final int COUNT_BITS = Integer.SIZE - 3;        // 29
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;   // 2^29-1
    
    // 线程池状态(高三位)
    private static final int RUNNING    = -1 << COUNT_BITS; // 接收新任务,处理队列任务
    private static final int SHUTDOWN   =  0 << COUNT_BITS; // 不接收新任务,但处理队列任务
    private static final int STOP       =  1 << COUNT_BITS; // 不接收新任务,不处理队列任务
    private static final int TIDYING    =  2 << COUNT_BITS; // 所有任务已终止
    private static final int TERMINATED =  3 << COUNT_BITS; // 已完成Terminated()钩子方法
    
    // 任务队列
    private final BlockingQueue<Runnable> workQueue;
    
    // 可重入锁:保护线程集合的访问
    private final ReentrantLock mainLock = new ReentrantLock();
    
    // 存储工作线程的集合
    private final HashSet<Worker> workers = new HashSet<Worker>();
    
    // 其他核心属性...
    private final int corePoolSize;           // 核心线程数
    private final int maximumPoolSize;        // 最大线程数
    private final long keepAliveTime;         // 空闲线程存活时间
    private final ThreadFactory threadFactory;// 线程工厂
    private final RejectedExecutionHandler rejectedExecutionHandler; // 拒绝策略
}

ctl 属性解析:

ctl = 原子整数,同时保存"线程池状态""工作线程数"

        32位整数
        ┌─────────┬────────────────────────────────┐
        │ 高3位    │ 低29位                          │
        │ 状态位   │ 线程数                           │
        └─────────┴────────────────────────────────┘

RUNNING:    111 00000...  = -1 << 29 = -536870912
SHUTDOWN:   000 00000...  =  0 << 29 = 0
STOP:       001 00000...  =  1 << 29 = 536870912
TIDYING:    010 00000...  =  2 << 29 = 1073741824
TERMINATED: 011 00000...  =  3 << 29 = 1610612736

3.2 任务提交 execute() 方法源码解析

execute()方法是线程池最核心的方法:

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    
    int c = ctl.get();
    
    // ====== 第一步:检查工作线程数是否小于核心线程数 ======
    if (workerCountOf(c) < corePoolSize) {
        // 添加新核心线程执行任务
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    
    // ====== 第二步:尝试将任务加入队列 ======
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        
        // 重新检查:如果线程池已不是RUNNING状态,移除任务
        if (!isRunning(recheck) && remove(command)) {
            reject(command);  // 执行拒绝策略
        }
        // 如果工作线程数为0,创建新的核心线程(队列可能有其他任务)
        else if (workerCountOf(recheck) == 0) {
            addWorker(null, false);
        }
    }
    // ====== 第三步:队列满了,尝试创建临时线程 ======
    else if (!addWorker(command, false))
        // ====== 第四步:都失败了,执行拒绝策略 ======
        reject(command);
}

流程图解:

                    ┌─────────────────┐
                       execute()    
                    └────────┬────────┘
                             
                             
                    ┌─────────────────┐
                     command == null?│
                    └────────┬────────┘
                             
              ┌──────────────┴──────────────┐
               Yes                          No
                                           
        ┌──────────┐              ┌─────────────────┐
         抛异常                  读取ctl值        
        └──────────┘              └────────┬────────┘
                                           
                              ┌────────────────────────┐
                               工作线程数 < 核心线程数 
                              └────────────┬───────────┘
                                           
                            ┌──────────────┴──────────────┐
                             Yes                          No
                                                         
                   ┌─────────────────┐          ┌─────────────────┐
                    addWorker(task,            进入任务队列     
                        true)                  workQueue.offer  
                   └────────┬────────┘          └────────┬────────┘
                                                       
              ┌──────────────┴──────────────┐           
               Success          Fail                 
                                                      
    ┌─────────────────┐           ┌─────────────────┐ ┌─────────────────┐
     返回,任务被                重新获取ctl        成功? 重新检查  
     核心线程执行                继续判断           失败? 拒绝任务  
    └─────────────────┘           └─────────────────┘ └─────────────────┘
                                                              
                                                              
                                                    ┌─────────────────┐
                                                     工作线程数=0?   
                                                    └────────┬────────┘
                                                             
                                                             
                                                    ┌─────────────────┐
                                                     创建新核心线程  
                                                     处理队列任务   
                                                    └─────────────────┘

3.3 addWorker() 源码解析

addWorker负责创建新线程并执行任务:

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        
        // 检查线程池状态:
        // 1. 不是RUNNING状态,不接收新任务
        // 2. 是SHUTDOWN状态,但firstTask不为空或队列为空,不创建新线程
        if (rs >= SHUTDOWN &&
            !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
            return false;
        
        for (;;) {
            int wc = workerCountOf(c);
            
            // 检查线程数是否超限
            if (wc >= (core ? corePoolSize : maximumPoolSize) ||
                wc >= CAPACITY)
                return false;
            
            // CAS增加工作线程数
            if (compareAndIncrementWorkerCount(c))
                break retry;
            
            c = ctl.get();
            if (runStateOf(c) != rs)
                continue retry;
        }
    }
    
    // 创建Worker并启动
    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                int rs = runStateOf(ctl.get());
                
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive())
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                }
            } finally {
                mainLock.unlock();
            }
            
            t.start();  // 启动线程
            workerAdded = true;
        }
    } finally {
        if (!workerAdded) {
            addWorkerFailed(w);
        }
    }
    return workerAdded;
}

3.4 Worker 类:线程池的工作者

Worker是线程池内部的工作单元:

private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
    
    final Thread thread;           // 执行任务的线程
    Runnable firstTask;            // 第一个任务(可选)
    volatile long completedTasks; // 完成的任务数
    
    Worker(Runnable firstTask) {
        this.firstTask = firstTask;
        // 使用线程工厂创建线程,注意this作为Runnable传入
        this.thread = getThreadFactory().newThread(this);
    }
    
    // 核心方法:执行任务
    public void run() {
        runWorker(this);
    }
    
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // 允许中断
        
        boolean completedAbruptly = true;
        try {
            // 循环取任务:先取firstTask,再从队列取
            while (task != null || (task = getTask()) != null) {
                w.lock();
                
                // 如果线程池STOP,确保线程被中断
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                
                try {
                    beforeExecute(wt, task);
                    try {
                        task.run();  // 执行任务
                        afterExecute(task, null);
                    } catch (RuntimeException x) {
                        afterExecute(task, x);
                        throw x;
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }
}

Worker的工作流程:

                    ┌─────────────────┐
                    │   线程启动       │
                    └────────┬────────┘
                             │
                             ▼
                    ┌─────────────────┐
                    │ 有firstTask?    │
                    └────────┬────────┘
                             │
              ┌──────────────┴──────────────┐
              │ Yes                         │ No
              ▼                             ▼
    ┌─────────────────┐           ┌─────────────────┐
    │ 执行firstTask   │           │ 从队列取任务     │
    └────────┬────────┘           │ getTask()       │
             │                    └────────┬────────┘
             │                             │
             └──────────────┬──────────────┘
                            │
                            ▼
                   ┌─────────────────┐
                   │ 任务执行中       │
                   │ beforeExecute() │
                   │   task.run()    │
                   │ afterExecute()  │
                   └────────┬────────┘
                            │
                            ▼
                   ┌─────────────────┐
                   │ 队列还有任务?   │
                   └────────┬────────┘
                            │
              ┌──────────────┴──────────────┐
              │ Yes                         │ No
              ▼                             ▼
        ┌─────────────┐              ┌─────────────────┐
        │ 继续取任务  │              │ 线程退出/回收    │
        └─────────────┘              └─────────────────┘

3.5 getTask() 源码解析

getTask()从队列获取任务:

private Runnable getTask() {
    boolean timedOut = false; // 标识上次poll是否超时
    
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        
        // 检查是否需要退出线程
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }
        
        int wc = workerCountOf(c);
        
        // 是否需要回收线程?
        // 1. 核心线程可以被回收(allowCoreThreadTimeOut)
        // 2. 或者工作线程数大于核心线程数
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }
        
        try {
            // 从队列取任务
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();  // 阻塞直到有任务
            
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

关键点:

  • 如果 allowCoreThreadTimeOut=true,核心线程也会超时被回收
  • 如果工作线程数 > 核心线程数,非核心线程会超时被回收
  • 使用 poll() 可以超时返回,take() 阻塞等待

四、Spring框架中的线程池

4.1 Spring TaskExecutor

Spring定义了TaskExecutor接口,屏蔽了Java Executor的差异:

public interface TaskExecutor extends Executor {
    void execute(Runnable task);
}

Spring内置的TaskExecutor实现:

实现类说明
SyncTaskExecutor同步执行器,在主线程执行(用于测试)
SimpleThreadPoolTaskExecutor包装Java的SimpleThreadPool
ThreadPoolTaskExecutor最常用的实现,包装ThreadPoolExecutor
ConcurrentTaskExecutor包装Java的Concurrent.ThreadPoolExecutor
WorkManagerTaskExecutor集成CommonJ WorkManager

4.2 ThreadPoolTaskExecutor 详解

ThreadPoolTaskExecutor是Spring最常用的线程池实现:

XML配置方式:

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="5"/>
    <property name="maxPoolSize" value="10"/>
    <property name="queueCapacity" value="200"/>
    <property name="threadNamePrefix" value="spring-task-"/>
    <property name="keepAliveSeconds" value="60"/>
    <property name="waitForTasksToCompleteOnShutdown" value="true"/>
    <property name="awaitTerminationSeconds" value="60"/>
</bean>

Java配置方式(推荐):

@Configuration
public class AsyncConfig {
    
    @Bean("taskExecutor")
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        
        // 核心线程数
        executor.setCorePoolSize(5);
        // 最大线程数
        executor.setMaxPoolSize(10);
        // 队列容量
        executor.setQueueCapacity(200);
        // 线程名前缀
        executor.setThreadNamePrefix("spring-task-");
        // 空闲线程存活时间
        executor.setKeepAliveSeconds(60);
        // 拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 是否等待任务完成再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 等待时间
        executor.setAwaitTerminationSeconds(60);
        
        executor.initialize();
        return executor;
    }
}

4.3 @Async 异步执行注解

Spring的@Async注解可以让方法异步执行:

@Service
public class AsyncService {
    
    // 使用自定义线程池
    @Async("taskExecutor")
    public void asyncMethod1() {
        System.out.println("异步任务1:" + Thread.currentThread().getName());
    }
    
    // 使用默认线程池(SimpleAsyncTaskExecutor,不复用线程)
    @Async
    public void asyncMethod2() {
        System.out.println("异步任务2:" + Thread.currentThread().getName());
    }
    
    // 带返回值
    @Async("taskExecutor")
    public CompletableFuture<String> asyncMethod3() {
        return CompletableFuture.completedFuture("异步结果");
    }
}

启动类需要开启异步支持:

@SpringBootApplication
@EnableAsync  // 开启异步支持
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4.4 @Scheduled 定时任务

Spring的@Scheduled支持多种定时方式:

@Service
public class ScheduledService {
    
    // 每5秒执行一次
    @Scheduled(fixedRate = 5000)
    public void fixedRateTask() {
        System.out.println("fixedRate: " + new Date());
    }
    
    // 上次任务完成后,延迟3秒再执行
    @Scheduled(fixedDelay = 3000)
    public void fixedDelayTask() {
        System.out.println("fixedDelay: " + new Date());
    }
    
    // 初始延迟2秒,然后按fixedRate执行
    @Scheduled(initialDelay = 2000, fixedRate = 5000)
    public void initialDelayTask() {
        System.out.println("initialDelay + fixedRate: " + new Date());
    }
    
    // Cron表达式:每分钟执行一次
    @Scheduled(cron = "0 * * * * ?")
    public void cronTask() {
        System.out.println("cron: " + new Date());
    }
}

Cron表达式详解:

┌───────────── 秒 (0-59)
│ ┌───────────── 分钟 (0-59)
│ │ ┌───────────── 小时 (0-23)
│ │ │ ┌───────────── 日 (1-31)
│ │ │ │ ┌───────────── 月 (1-12)
│ │ │ │ │ ┌───────────── 星期 (1-7, 1=周日)
│ │ │ │ │ │ 
* * * * * *

示例:
"0 0 * * * ?"      每小时整点
"0 0 10 * * ?"     每天10点
"0 30 9 1 * ?"     每月19:30
"0/5 * * * * ?"5

开启定时任务:

@SpringBootApplication
@EnableScheduling  // 开启定时任务
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

五、实战:自定义线程池全攻略

5.1 为什么要自定义线程池?

场景使用Executors使用自定义ThreadPoolExecutor
任务数量可控✅ 可以✅ 可以
任务数量可能突增❌ 队列无界,可能OOM✅ 有界队列 + 拒绝策略
需要精细化配置❌ 无法配置✅ 核心线程数、最大线程数、空闲时间等
需要监控线程池状态❌ 无法监控✅ 提供监控接口
需要自定义线程名称❌ 默认名称✅ 自定义ThreadFactory
需要父子线程传递上下文❌ 无法实现✅ 可配合InheritableThreadLocal

5.2 通用线程池配置

根据不同业务场景,给出推荐配置:

CPU密集型任务(计算、加密、压缩等)

/**
 * CPU密集型任务配置
 * 
 * CPU密集型特点:
 * - 任务主要是计算,需要大量CPU时间
 * - 线程数不宜过多,因为CPU本身是瓶颈
 * - 推荐公式:CPU核心数 + 1
 * 
 * Java获取CPU核心数:Runtime.getRuntime().availableProcessors()
 */
public class CpuIntensiveConfig {
    
    public static ExecutorService createCpuIntensivePool() {
        int cpuCount = Runtime.getRuntime().availableProcessors();
        
        return new ThreadPoolExecutor(
            cpuCount,                 // 核心线程数
            cpuCount,                 // 最大线程数(CPU密集型不需要更多线程)
            0L,                       // 不需要回收,因为没有临时线程
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(100),  // 有界队列
            new ThreadFactoryBuilder()
                .setNameFormat("cpu-task-%d")
                .build(),
            new ThreadPoolExecutor.AbortPolicy()
        );
    }
}

IO密集型任务(网络请求、文件读写、数据库查询等)

/**
 * IO密集型任务配置
 * 
 * IO密集型特点:
 * - 任务大部分时间在等待IO(网络、磁盘、数据库)
 * - CPU经常空闲,可以创建更多线程
 * - 推荐公式:CPU核心数 * 2 或 CPU核心数 / (1 - 阻塞系数)
 * - 阻塞系数通常取0.8~0.9
 */
public class Io密集型Config {
    
    public static ExecutorService createIOIntensivePool() {
        int cpuCount = Runtime.getRuntime().availableProcessors();
        
        // IO密集型:2倍CPU核心数
        int corePoolSize = cpuCount * 2;
        // 最大线程数可以更大
        int maxPoolSize = cpuCount * 4;
        
        return new ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            60L,                      // 空闲线程存活时间
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(200),  // 有界队列
            new ThreadFactoryBuilder()
                .setNameFormat("io-task-%d")
                .setDaemon(false)    // 设置为非守护线程
                .build(),
            new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略:调用者执行
        );
    }
}

混合型任务(既有CPU计算又有IO)

/**
 * 混合型任务配置
 * 
 * 根据实际情况调整比例
 * 如果CPU计算多,增加核心线程数
 * 如果IO等待多,增加队列容量
 */
public class MixedTaskConfig {
    
    public static ExecutorService createMixedPool() {
        int cpuCount = Runtime.getRuntime().availableProcessors();
        
        return new ThreadPoolExecutor(
            cpuCount + 1,            // 核心线程数
            cpuCount * 2,            // 最大线程数
            30L,                     // 空闲存活时间
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(500),
            new ThreadFactoryBuilder()
                .setNameFormat("mixed-task-%d")
                .build(),
            new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }
}

5.3 完整的自定义线程池工具类

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**
 * 线程池工具类
 * 
 * 提供不同场景的线程池创建方法
 * 
 * @author 苏木
 */
public class ThreadPoolUtils {
    
    // 私有构造函数,防止实例化
    private ThreadPoolUtils() {}
    
    /**
     * 创建CPU密集型线程池
     */
    public static ExecutorService newCpuIntensivePool() {
        int corePoolSize = Runtime.getRuntime().availableProcessors();
        return new ThreadPoolExecutor(
            corePoolSize,
            corePoolSize,
            0L,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(100),
            new ThreadFactoryBuilder()
                .setNameFormat("cpu-intensive-%d")
                .setUncaughtExceptionHandler((t, e) -> {
                    System.err.println("线程 " + t.getName() + " 异常: " + e.getMessage());
                })
                .build(),
            new ThreadPoolExecutor.AbortPolicy()
        );
    }
    
    /**
     * 创建IO密集型线程池
     */
    public static ExecutorService newIOIntensivePool() {
        int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;
        int maxPoolSize = Runtime.getRuntime().availableProcessors() * 4;
        
        return new ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            60L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(200),
            new ThreadFactoryBuilder()
                .setNameFormat("io-intensive-%d")
                .setUncaughtExceptionHandler((t, e) -> {
                    System.err.println("线程 " + t.getName() + " 异常: " + e.getMessage());
                })
                .build(),
            new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }
    
    /**
     * 创建带监控的线程池
     */
    public static ExecutorService newMonitoredPool(
            int corePoolSize,
            int maxPoolSize,
            int queueCapacity,
            String poolName) {
        
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            60L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(queueCapacity),
            new ThreadFactoryBuilder()
                .setNameFormat(poolName + "-%d")
                .build(),
            new ThreadPoolExecutor.AbortPolicy()
        );
        
        // 添加监控任务
        ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor(
            r -> {
                Thread t = new Thread(r);
                t.setName(poolName + "-monitor");
                t.setDaemon(true);
                return t;
            }
        );
        
        // 每5秒打印一次线程池状态
        monitor.scheduleAtFixedRate(() -> {
            printThreadPoolStatus(executor, poolName);
        }, 0, 5, TimeUnit.SECONDS);
        
        return executor;
    }
    
    /**
     * 打印线程池状态
     */
    public static void printThreadPoolStatus(ThreadPoolExecutor executor, String poolName) {
        StringBuilder sb = new StringBuilder();
        sb.append("\n========== ").append(poolName).append(" 状态 ==========\n");
        sb.append(String.format("  核心线程数: %d\n", executor.getCorePoolSize()));
        sb.append(String.format("  最大线程数: %d\n", executor.getMaximumPoolSize()));
        sb.append(String.format("  当前线程数: %d\n", executor.getPoolSize()));
        sb.append(String.format("  活跃线程数: %d\n", executor.getActiveCount()));
        sb.append(String.format("  队列大小: %d\n", executor.getQueue().size()));
        sb.append(String.format("  完成任务数: %d\n", executor.getCompletedTaskCount()));
        sb.append(String.format("  总任务数: %d\n", executor.getTaskCount()));
        sb.append("===================================\n");
        
        System.out.println(sb.toString());
    }
}

5.4 线程池使用最佳实践

public class ThreadPoolBestPractices {
    
    public static void main(String[] args) {
        ExecutorService executor = new ThreadPoolExecutor(
            5, 10, 60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),
            new ThreadFactoryBuilder()
                .setNameFormat("best-practice-%d")
                .build(),
            new ThreadPoolExecutor.CallerRunsPolicy()
        );
        
        try {
            // ✅ 正确做法1:使用try-with-resources或手动shutdown
            try (ExecutorService service = executor) {
                // 提交任务
                Future<String> future = executor.submit(() -> {
                    return doTask();
                });
                
                // ✅ 正确做法2:设置超时,避免无限等待
                String result = future.get(30, TimeUnit.SECONDS);
                System.out.println("任务结果: " + result);
            }
            
            // ✅ 正确做法3:使用shutdownNow尝试停止
            executor.shutdownNow();
            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                System.err.println("线程池未能在规定时间内终止");
            }
            
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        } catch (ExecutionException | TimeoutException e) {
            e.printStackTrace();
        }
    }
    
    private static String doTask() {
        return "Task completed";
    }
}

常见错误:

public class ThreadPoolMistakes {
    
    // ❌ 错误1:线程池变量定义为ExecutorService,但实际使用Executors
    // 这会导致代码中到处使用newFixedThreadPool,无法统一管理
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    
    // ✅ 正确:定义为成员变量,使用统一配置
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
        5, 10, 60L, TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(100),
        new ThreadFactoryBuilder().setNameFormat("task-%d").build(),
        new ThreadPoolExecutor.AbortPolicy()
    );
    
    // ❌ 错误2:任务抛出异常后未处理
    public void badSubmit() {
        executor.submit(() -> {
            throw new RuntimeException("任务失败");  // 异常会被吞噬
        });
    }
    
    // ✅ 正确:使用execute或捕获异常
    public void goodSubmit() {
        executor.execute(() -> {
            try {
                doSomething();
            } catch (Exception e) {
                // 处理异常
                handleException(e);
            }
        });
    }
    
    // ❌ 错误3:忘记关闭线程池
    public void forgotShutdown() {
        ExecutorService executor = Executors.newFixedThreadPool(10);
        // 使用完后忘记executor.shutdown()
        // 导致JVM无法正常退出
    }
}

六、框架线程池 vs 自定义线程池:深度对比

6.1 功能对比

特性Spring TaskExecutor自定义ThreadPoolExecutor
参数配置XML/Java配置完全可定制
与Spring容器集成✅ 自动管理生命周期❌ 需手动管理
@Async异步支持✅ 支持❌ 需要配合其他方案
@Scheduled定时支持✅ 支持❌ 需要配合ScheduledExecutorService
监控基础监控可完全自定义监控
线程复用✅ 支持✅ 支持
拒绝策略可配置可配置
线程工厂默认实现完全可定制

6.2 性能对比

/**
 * 性能测试对比
 */
public class PerformanceComparison {
    
    public static void main(String[] args) throws Exception {
        // Spring风格的线程池
        ThreadPoolTaskExecutor springExecutor = new ThreadPoolTaskExecutor();
        springExecutor.setCorePoolSize(10);
        springExecutor.setMaxPoolSize(20);
        springExecutor.setQueueCapacity(100);
        springExecutor.setThreadNamePrefix("spring-");
        springExecutor.initialize();
        
        // 自定义线程池
        ExecutorService customExecutor = new ThreadPoolExecutor(
            10, 20, 60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),
            r -> {
                Thread t = new Thread(r);
                t.setName("custom-" + t.getId());
                return t;
            },
            new ThreadPoolExecutor.AbortPolicy()
        );
        
        int taskCount = 10000;
        IntStream.range(0, taskCount).forEach(i -> {
            // 模拟CPU计算任务
            Runnable task = () -> {
                long sum = 0;
                for (int j = 0; j < 1000; j++) {
                    sum += Math.random();
                }
            };
            
            springExecutor.execute(task);
            customExecutor.execute(task);
        });
        
        springExecutor.shutdown();
        customExecutor.shutdown();
    }
}

6.3 适用场景

┌─────────────────────────────────────────────────────────────────┐
                     选择决策树                                   
                                                                  
                    ┌───────────────┐                             
                      你是Spring项目?│                           
                    └───────┬───────┘                             
                                                                 
              ┌─────────────┴─────────────┐                      
               Yes                           No                 
                                                                
    ┌─────────────────────┐        ┌─────────────────────┐        
     需要@Async/@Scheduled?│         需要完全自定义?             
    └─────────┬───────────┘        └─────────┬───────────┘        
                                                                  
    ┌─────────┴─────────┐                                          
     Yes                 No                                       
                                                                  
 ┌────────────┐  ┌────────────┐        ┌─────────────────────┐   
  ThreadPool    Spring              ThreadPoolExecutor     
  TaskExecutor│   SimpleAsync│         (完全自定义)            
  @Async         TaskExecutor│                               
 └────────────┘  └────────────┘        └─────────────────────┘   
                                                                  
    适用场景:                            适用场景:              
     Spring Boot项目                     非Spring项目           
     需要异步/定时支持                     需要精细化控制          
     与Spring容器集成                     特殊监控需求            
└─────────────────────────────────────────────────────────────────┘

6.4 实战建议

Spring项目:

@Configuration
@EnableAsync
@EnableScheduling
public class SpringThreadPoolConfig {
    
    /**
     * 普通异步任务线程池
     */
    @Bean("asyncExecutor")
    public ThreadPoolTaskExecutor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }
    
    /**
     * 定时任务线程池
     */
    @Bean("scheduledExecutor")
    public ScheduledExecutorService scheduledExecutor() {
        return Executors.newScheduledThreadPool(
            5,
            new ThreadFactoryBuilder()
                .setNameFormat("scheduled-%d")
                .build()
        );
    }
}

非Spring项目:

/**
 * 非Spring环境下的线程池管理
 */
public class ThreadPoolManager {
    
    private static volatile ThreadPoolManager instance;
    private final Map<String, ExecutorService> threadPools = new ConcurrentHashMap<>();
    
    private ThreadPoolManager() {}
    
    public static ThreadPoolManager getInstance() {
        if (instance == null) {
            synchronized (ThreadPoolManager.class) {
                if (instance == null) {
                    instance = new ThreadPoolManager();
                }
            }
        }
        return instance;
    }
    
    /**
     * 注册线程池
     */
    public void register(String name, ExecutorService executor) {
        threadPools.put(name, executor);
    }
    
    /**
     * 获取线程池
     */
    public ExecutorService get(String name) {
        return threadPools.get(name);
    }
    
    /**
     * 关闭所有线程池
     */
    public void shutdownAll() {
        threadPools.values().forEach(executor -> {
            executor.shutdown();
            try {
                if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        });
    }
    
    /**
     * JVM关闭时自动关闭所有线程池
     */
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::shutdownAll));
    }
}

七、面试重点总结

7.1 必问知识点

Q1: 线程池的工作流程是什么?

1. 线程池收到任务
2. 判断当前工作线程数是否 < 核心线程数
   - 是:创建新核心线程执行任务
   - 否:进入下一步
3. 判断任务队列是否已满
   - 否:将任务加入队列等待
   - 是:进入下一步
4. 判断当前线程数是否 < 最大线程数
   - 是:创建临时线程执行任务
   - 否:执行拒绝策略

Q2: 线程池有哪几种拒绝策略?

策略说明
AbortPolicy默认策略,抛出RejectedExecutionException
CallerRunsPolicy由调用者线程执行任务
DiscardPolicy直接丢弃任务
DiscardOldestPolicy丢弃队列中最老的任务,然后重试

Q3: 如何合理配置线程池参数?

- CPU密集型:核心线程数 = CPU核心数 + 1
- IO密集型:核心线程数 = CPU核心数 * 2(或更大)
- 混合型:根据实际情况调整

队列容量设置:
- 预估最大任务数
- 设置队列容量 = 最大任务数 - 核心线程数

Q4: execute()和submit()的区别?

// execute():用于提交不需要返回值的任务
executor.execute(() -> System.out.println("任务执行"));

// submit():用于提交需要返回值的任务,返回Future
Future<String> future = executor.submit(() -> "结果");
String result = future.get();  // 阻塞获取结果

Q5: 线程池如何实现线程复用?

Worker类实现:
1. 每个Worker持有一个Thread和一个Runnable
2. Worker.run()调用runWorker()
3. runWorker()内部循环调用getTask()
4. getTask()从队列获取任务
5. 任务执行完后,继续取下一个任务
6. 没有任务时,线程阻塞等待(take())或超时等待(poll())

7.2 知识图谱

┌──────────────────────────────────────────────────────────────────┐
│                        Java线程池知识图谱                         │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                        线程池基础                         │   │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐        │   │
│  │  │  为什么要 │ │  核心参数 │ │  工作流程 │ │  状态转换 │        │   │
│  │  │  用线程池 │ │          │ │          │ │          │        │   │
│  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘        │   │
│  └──────────────────────────────────────────────────────────┘   │
│                              │                                   │
│                              ▼                                   │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                    Executor框架                           │   │
│  │  ┌─────────────────────────────────────────────────────┐  │   │
│  │  │  Executors工具类                                     │  │   │
│  │  │  newFixedThreadPool / newCachedThreadPool           │  │   │
│  │  │  newSingleThreadExecutor / newScheduledThreadPool   │  │   │
│  │  └─────────────────────────────────────────────────────┘  │   │
│  │  ┌─────────────────────────────────────────────────────┐  │   │
│  │  │  ThreadPoolExecutor                                 │  │   │
│  │  │  execute() / submit() / shutdown()                  │  │   │
│  │  └─────────────────────────────────────────────────────┘  │   │
│  └──────────────────────────────────────────────────────────┘   │
│                              │                                   │
│                              ▼                                   │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                    框架集成                               │   │
│  │  ┌──────────────────┐    ┌──────────────────────────────┐ │   │
│  │  │  Spring TaskExec │    │  Spring @Async/@Scheduled  │ │   │
│  │  └──────────────────┘    └──────────────────────────────┘ │   │
│  └──────────────────────────────────────────────────────────┘   │
│                              │                                   │
│                              ▼                                   │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                    最佳实践                               │   │
│  │  • 使用ThreadPoolExecutor而非Executors                    │   │
│  │  • 合理配置核心线程数和队列容量                            │   │
│  │  • 选择合适的拒绝策略                                      │   │
│  │  • 线程池关闭和监控                                        │   │
│  └──────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────┘

结语

这篇文章我们从线程池的基础概念出发,深入源码剖析了ThreadPoolExecutor的实现原理,对比分析了框架自带线程池和自定义线程池的区别。

核心要点回顾:

  1. 线程池是复用线程的机制,避免反复创建销毁线程的开销
  2. Java原生线程池通过Executor框架提供,Executors工具类提供了4种常用线程池
  3. ThreadPoolExecutor是核心实现,execute()方法遵循"核心→队列→最大→拒绝"的执行流程
  4. Spring TaskExecutor是对Java Executor的抽象,与Spring容器深度集成
  5. 自定义线程池在任务量大、需要精细化控制时是更好的选择
  6. 阿里巴巴规范明确禁止使用Executors创建线程池,推荐使用ThreadPoolExecutor

希望这篇文章能帮助大家彻底理解Java线程池,在实际开发中写出更优雅、更高效的并发代码!

如果对你有帮助,一键三连支持一下~


本文首发于掘金,同步更新于CSDN

更多优质内容,欢迎关注我的博客