线程池(ThreadPoolExecutor)实现原理和源码细节是Java高并发面试和实战开发的重点


一、线程池核心流程图

+-----------------+
|    提交任务      | submit/execute
+-----------------+
         |
         v
+-----------------+
| 判断核心线程数  | < corePoolSize?
+-----------------+
   |Yes        |No
   v           v
[创建新线程]   +-----------------+
              | 队列是否满?     |
              +-----------------+
                  |No        |Yes
                  v           v
            [入队列排队]   +------------------+
                           | 判断最大线程数  |
                           +------------------+
                              |No          |Yes
                              v             v
                       [创建新线程]   [执行拒绝策略]

二、线程池主要环节及源码方法

1. 任务提交(execute/submit)

方法:

  • execute(Runnable command)
  • submit(Runnable/Callable)

源码片段:

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();
        if (!isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

注释速记:

  • 任务先尝试用核心线程处理。
  • 核心线程满则尝试入队列。
  • 队列满则尝试新建非核心线程。
  • 实在不行,执行拒绝策略。

口诀:
先核心,后队列;队列满,再扩容;全满员,拒绝它。


2. 核心线程判断与创建

方法:

  • addWorker(Runnable firstTask, boolean core)

源码片段:

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // ...省略状态判断
        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();
            if (runStateOf(c) != rs)
                continue retry;
        }
    }
    // ...真正创建Worker线程
}

注释速记:

  • 根据core参数决定是否用核心线程池大小。
  • 用CAS增加线程计数,线程安全。

口诀:
核心先上,CAS抢位,线程安全,才创建。


3. 入队列

方法:

  • workQueue.offer(command)

源码片段:

if (isRunning(c) && workQueue.offer(command)) {
    // 入队成功后可能需要唤醒线程
}

注释速记:

  • 队列没满则入队。
  • 入队后如果线程都在忙,线程池不会立刻扩容。

口诀:
队列能放,直接排队。


4. 非核心线程扩容

逻辑:

  • 当核心线程和队列都满时,允许创建新线程(最大线程数以内)。

源码片段:

else if (!addWorker(command, false))
    reject(command);

注释速记:

  • 只有在核心线程和队列都满时才会扩容到最大线程数。

口诀:
满员排队,再扩容。


5. 拒绝策略

方法:

  • RejectedExecutionHandler.rejectedExecution(Runnable r, ThreadPoolExecutor e)

源码片段:

public static class AbortPolicy implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException();
    }
}

注释速记:

  • 线程池和队列都满时,根据策略处理(抛异常/丢弃/调用者执行等)。

口诀:
全都满员,策略管。


6. 线程回收与销毁

方法:

  • worker.run()
  • 判断空闲时间超过keepAliveTime

源码片段:

while (task != null || (task = getTask()) != null) {
    // 执行任务
}

注释速记:

  • 非核心线程空闲时间到达后会被回收。
  • 核心线程默认不会被回收(可通过allowCoreThreadTimeOut配置)。

口诀:
闲太久,自动走。


三、流程口诀速记

提任务,先核心,队列排,扩满员;全满员,策略管;空闲久,自动走。


四、常用方法与内部逻辑简表

阶段关键方法/类主要逻辑说明
任务提交execute/submit任务进线程池
核心线程判断addWorker(core=true)核心线程是否有空位,有则新建
入队列workQueue.offer核心线程满,队列没满则排队
非核心线程addWorker(core=false)队列满,是否可新建非核心线程
拒绝策略RejectedExecutionHandler全部满员,执行拒绝策略
线程回收allowCoreThreadTimeOut非核心线程闲置超时自动销毁

五、源码脉络图(伪代码)

execute(command) {
    if (核心线程未满)
        addWorker(command, true)  // 新核心线程
    else if (队列未满)
        workQueue.offer(command)  // 入队列
    else if (线程池未满)
        addWorker(command, false) // 新非核心线程
    else
        reject(command)           // 拒绝策略
}

六、速记口诀总结

场景口诀
任务进池先核心,后队列
队列满了再扩容(到最大线程数)
全满员策略管(拒绝策略)
线程回收闲太久,自动走
全流程提任务,先核心,队列排,扩满员;全满员,策略管;空闲久,自动走。

七、配图(流程图)

         +-------------------------+
         |      提交任务           |
         +-------------------------+
                    |
      +-------------+-------------+
      |                           |
+-----v-----+               +-----v-----+
| 核心线程? |----是-------->| 创建线程  |
+-----------+               +-----------+
      |
      否
      |
+-----v-----+
| 队列满?   |----否-------> 入队列
+-----------+
      |
      是
      |
+-----v-----+
| 最大线程? |----否-------> 创建线程
+-----------+
      |
      是
      |
+-----v-----+
| 拒绝策略  |
+-----------+

八、结语

通过以上细化,线程池的工作原理、源码关键点、方法流程、口诀速记都一目了然。
只要记住口诀和流程图,结合源码细节,面试和实战都能轻松拿捏!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北漂老男人

防秃基金【靠你的打赏续命】

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值