【Java并发编程】线程池:核心7大参数、执行原理、execute() vs submit()、拒绝策略、参数设计、动态线程池、线程池隔离(附《思维导图》+《面试高频考点清单》)

简介: 本文系统梳理Java线程池全体系知识:涵盖7大核心参数原理、任务执行四步流程、execute与submit本质区别、4种拒绝策略适用场景、CPU/IO密集型线程数计算方法,并强调禁用Executors、必用有界队列、自定义线程工厂等生产级最佳实践,助力高效并发编程与面试通关。

思维导图

Java并发编程:线程池全体系知识总结

一、线程池基础概述

1.1 核心定义

线程池是一种池化资源管理技术,通过预先创建一定数量的线程并统一管理,实现任务的异步执行与资源复用。它解决了频繁创建销毁线程的性能开销问题,同时提供了任务排队、并发控制、监控统计等能力。

1.2 核心优势

  • 降低资源消耗:复用已创建的线程,避免线程创建销毁的系统开销
  • 提高响应速度:任务到达时无需等待线程创建即可执行
  • 提高线程可管理性:统一分配、调优和监控线程资源
  • 提供附加功能:定时执行、并发控制、任务排队等

1.3 核心设计思想

基于生产者-消费者模型

  • 生产者:提交任务的线程
  • 消费者:线程池中的工作线程
  • 缓冲区:任务队列(BlockingQueue)

二、线程池核心7大参数详解

ThreadPoolExecutor的完整构造方法:

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

2.1 corePoolSize(核心线程数)

  • 定义:线程池长期保持的存活线程数量,即使处于空闲状态也不会被销毁
  • 特性
    • 默认情况下,核心线程会一直存活
    • 调用allowCoreThreadTimeOut(true)可允许核心线程超时销毁
    • 线程池初始化时不会立即创建核心线程,而是在任务提交时懒加载
  • 面试考点:核心线程是"常驻员工",负责处理常规任务

2.2 maximumPoolSize(最大线程数)

  • 定义:线程池允许创建的最大线程数量
  • 特性
    • 当核心线程已满且工作队列已满时,线程池会创建新线程直到达到该值
    • 包含核心线程和非核心线程两部分
  • 面试考点:非核心线程是"临时工",任务高峰期临时增加,空闲后会被销毁

2.3 keepAliveTime(空闲线程存活时间)

  • 定义:非核心线程空闲后的存活时间
  • 特性
    • 当线程空闲时间超过该值时,非核心线程会被销毁
    • 若设置allowCoreThreadTimeOut(true),核心线程也会受此参数影响
  • 使用场景:任务执行时间短、任务量波动大的场景可适当调大该值

2.4 unit(时间单位)

  • 定义keepAliveTime的时间单位
  • 可选值TimeUnit.MILLISECONDSTimeUnit.SECONDSTimeUnit.MINUTES

2.5 workQueue(工作队列)

  • 定义:用于存储等待执行任务的阻塞队列
  • 常见实现
队列类型 特点 适用场景
ArrayBlockingQueue 有界阻塞队列,基于数组实现,FIFO 任务量可控,需要限制队列长度的场景
LinkedBlockingQueue 无界/有界阻塞队列,基于链表实现,FIFO 任务量波动大,吞吐量要求高的场景
SynchronousQueue 不存储元素的阻塞队列,直接将任务交给线程 任务执行时间短,并发量高的场景
PriorityBlockingQueue 支持优先级的无界阻塞队列 需要按优先级执行任务的场景
DelayQueue 延迟队列,元素只有在延迟期满后才能被获取 定时任务、超时处理等场景
  • 面试考点Executors.newFixedThreadPool()使用无界LinkedBlockingQueue,可能导致OOM

2.6 threadFactory(线程工厂)

  • 定义:用于创建线程的工厂类
  • 作用
    • 自定义线程名称(便于问题排查)
    • 设置线程优先级
    • 设置是否为守护线程
    • 设置线程组
  • 最佳实践永远使用自定义线程工厂,不要使用默认的DefaultThreadFactory
  • 示例
    ThreadFactory threadFactory = new ThreadFactoryBuilder()
      .setNameFormat("order-pool-%d")
      .setDaemon(false)
      .setPriority(Thread.NORM_PRIORITY)
      .build();
    

2.7 handler(拒绝策略)

  • 定义:当线程池无法处理新任务时的处理策略
  • 触发条件
    • 线程池已关闭
    • 最大线程数已满且工作队列已满
  • JDK内置4种拒绝策略:见下文"四、拒绝策略详解"

三、线程池执行原理

3.1 任务提交完整流程(核心考点)

  1. 判断核心线程数是否已满

    • 未满:创建新的核心线程执行任务
    • 已满:进入下一步
  2. 判断工作队列是否已满

    • 未满:将任务加入工作队列等待执行
    • 已满:进入下一步
  3. 判断最大线程数是否已满

    • 未满:创建新的非核心线程执行任务
    • 已满:执行拒绝策略

流程图

任务提交
    ↓
核心线程数 < corePoolSize? → 是 → 创建核心线程执行
    ↓否
工作队列未满? → 是 → 加入队列等待
    ↓否
当前线程数 < maximumPoolSize? → 是 → 创建非核心线程执行
    ↓否
执行拒绝策略

3.2 线程池状态流转

线程池有5种状态:

  • RUNNING:接受新任务并处理队列中的任务
  • SHUTDOWN:不接受新任务,但会处理队列中的剩余任务
  • STOP:不接受新任务,不处理队列中的任务,中断正在执行的任务
  • TIDYING:所有任务已终止,workerCount为0,即将执行terminated()方法
  • TERMINATEDterminated()方法执行完成,线程池彻底终止

状态流转

RUNNING → SHUTDOWN → TIDYING → TERMINATED
RUNNING → STOP → TIDYING → TERMINATED

3.3 工作线程(Worker)的生命周期

  1. 线程池创建Worker对象,启动线程
  2. Worker不断从工作队列中获取任务执行
  3. 若获取不到任务(队列空),则进入空闲状态
  4. 空闲时间超过keepAliveTime且当前线程数大于corePoolSize,则销毁该线程
  5. 若设置了allowCoreThreadTimeOut(true),核心线程也会被销毁

四、execute() vs submit() 深度对比

4.1 方法签名与返回值

  • execute()

    void execute(Runnable command);
    
    • 只能接收Runnable类型任务
    • 无返回值
  • submit()

    Future<?> submit(Runnable task);
    <T> Future<T> submit(Runnable task, T result);
    <T> Future<T> submit(Callable<T> task);
    
    • 可接收RunnableCallable类型任务
    • 返回Future对象,可获取任务执行结果

4.2 异常处理差异(核心考点)

  • execute()

    • 任务执行时抛出的未检查异常会直接打印堆栈
    • 异常会导致当前工作线程终止,线程池会创建新线程替代
    • 无法通过Future捕获异常
  • submit()

    • 任务执行时抛出的异常会被封装到Future对象中
    • 只有调用Future.get()方法时才会抛出ExecutionException
    • 不会导致工作线程终止
    • 可以通过Future捕获并处理异常

4.3 使用场景对比

方法 适用场景 不适用场景
execute() 不需要获取执行结果的异步任务 需要获取结果或处理异常的任务
submit() 需要获取执行结果或处理异常的任务 简单的异步任务(增加不必要的Future开销)

4.4 底层实现关系

submit()方法底层最终还是调用execute()方法:

public <T> Future<T> submit(Callable<T> task) {
   
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

五、拒绝策略详解

5.1 JDK内置4种拒绝策略

  1. AbortPolicy(默认策略)

    • 直接抛出RejectedExecutionException异常
    • 特点:简单直接,能快速感知任务被拒绝
    • 适用场景:关键业务,不能容忍任务丢失的场景
  2. CallerRunsPolicy

    • 由提交任务的线程自己执行该任务
    • 特点:
      • 不会丢失任务
      • 会降低任务提交速度,起到流量控制作用
    • 适用场景:对任务丢失零容忍,且流量可控的场景
  3. DiscardPolicy

    • 直接丢弃任务,不做任何处理
    • 特点:最简单,但会导致任务丢失
    • 适用场景:非核心业务,允许任务丢失的场景
  4. DiscardOldestPolicy

    • 丢弃队列中最旧的任务(队首任务),然后重新提交当前任务
    • 特点:会丢弃最早的任务,保留最新的任务
    • 适用场景:消息处理等允许丢弃旧消息的场景

5.2 自定义拒绝策略

实现RejectedExecutionHandler接口:

public class CustomRejectedPolicy implements RejectedExecutionHandler {
   
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
   
        // 自定义处理逻辑
        log.error("任务被拒绝,线程池状态:{}", executor);
        // 例如:记录日志、持久化任务、降级处理等
    }
}

5.3 生产环境推荐策略

  • 核心业务AbortPolicy + 全局异常捕获 + 告警
  • 非核心业务CallerRunsPolicy(流量控制)或自定义持久化策略
  • 消息处理DiscardOldestPolicy(允许丢弃旧消息)

六、线程池参数设计最佳实践

6.1 核心线程数计算(核心考点)

6.1.1 传统计算方法

  • CPU密集型任务

    corePoolSize = CPU核心数 + 1
    
    • 原因:CPU密集型任务几乎没有IO等待,线程数过多会导致上下文切换开销
  • IO密集型任务

    corePoolSize = CPU核心数 * 2
    

    或更精确的公式:

    corePoolSize = CPU核心数 * (1 + 平均等待时间 / 平均CPU时间)
    
    • 原因:IO密集型任务大部分时间在等待IO,线程数多可以提高CPU利用率

6.1.2 生产环境实际做法

  • 压测调优法:先根据经验设置初始值,然后通过压测观察CPU利用率、响应时间、吞吐量等指标,逐步调整
  • 动态调整法:使用动态线程池,根据系统负载自动调整参数

6.2 其他参数设计原则

  • maximumPoolSize

    • 一般设置为corePoolSize的2-4倍
    • 避免设置过大导致系统资源耗尽
    • 对于SynchronousQueuemaximumPoolSize应设置得大一些
  • keepAliveTime

    • 任务执行时间短:设置较短(如60秒)
    • 任务执行时间长:设置较长(如5分钟)
    • 核心业务:可设置为0(不允许非核心线程空闲)
  • 工作队列

    • 永远不要使用无界队列(可能导致OOM)
    • 优先使用ArrayBlockingQueue(有界,可控)
    • 队列长度一般设置为corePoolSize * 2或根据业务峰值调整
  • 线程工厂

    • 必须自定义线程名称,便于问题排查
    • 设置合理的线程优先级
    • 不要设置为守护线程(避免JVM退出时任务被强制终止)

6.3 常见参数配置错误

  1. 核心线程数设置过大:导致上下文切换频繁,CPU利用率低
  2. 最大线程数设置过大:导致系统资源耗尽,OOM
  3. 使用无界队列:任务堆积导致OOM
  4. 拒绝策略设置不当:导致任务丢失或系统崩溃
  5. 线程池未关闭:导致应用无法正常退出

七、动态线程池

7.1 为什么需要动态线程池

  • 静态参数的局限性
    • 业务流量是动态变化的,静态参数无法适应所有场景
    • 流量高峰时线程池参数过小导致任务堆积
    • 流量低谷时线程池参数过大导致资源浪费
  • 动态调整的优势
    • 无需重启应用即可调整参数
    • 提高系统的弹性和适应性
    • 降低运维成本

7.2 可动态调整的参数

  • corePoolSize:核心线程数
  • maximumPoolSize:最大线程数
  • keepAliveTime:空闲线程存活时间
  • 工作队列容量(部分实现支持)
  • 拒绝策略

7.3 实现原理

  1. 参数存储:将线程池参数存储在配置中心(Nacos、Apollo等)
  2. 参数监听:监听配置中心的参数变化
  3. 动态更新:参数变化时调用ThreadPoolExecutor的setter方法更新
  4. 平滑过渡:确保参数更新过程中不会影响正在执行的任务

7.4 主流实现方案

7.4.1 美团动态线程池(DynamicTp)

  • 开源地址:https://github.com/dromara/dynamic-tp
  • 核心特性:
    • 基于配置中心实现参数动态调整
    • 支持多种线程池类型(普通、定时、优先级等)
    • 丰富的监控指标(线程数、队列长度、任务执行时间等)
    • 告警功能(任务堆积、拒绝、超时等)
    • 支持线程池隔离

7.4.2 阿里Sentinel线程池隔离

  • 基于Sentinel的限流熔断能力实现
  • 支持按资源隔离线程池
  • 动态调整线程池参数
  • 集成监控和告警

7.5 监控与告警

  • 核心监控指标
    • 活跃线程数、核心线程数、最大线程数
    • 队列长度、队列剩余容量
    • 已完成任务数、拒绝任务数
    • 任务平均执行时间、最大执行时间
  • 告警阈值
    • 队列使用率超过80%
    • 拒绝任务数大于0
    • 活跃线程数接近最大线程数
    • 任务平均执行时间超过阈值

八、线程池隔离

8.1 什么是线程池隔离

线程池隔离是指将不同业务的任务分配到不同的线程池中执行,避免某个业务的异常导致整个系统的线程资源耗尽。

8.2 为什么需要线程池隔离

  • 问题场景
    • 某个业务接口响应变慢,导致线程池中的线程全部被阻塞
    • 其他业务无法获取线程资源,整个系统雪崩
  • 隔离的优势
    • 故障隔离:一个业务的异常不会影响其他业务
    • 资源隔离:不同业务使用独立的线程资源
    • 便于监控和调优:可以针对不同业务设置不同的线程池参数

8.3 隔离的维度

  1. 业务维度:按业务模块隔离(如订单、支付、用户等)
  2. 优先级维度:按任务优先级隔离(如高优先级、中优先级、低优先级)
  3. 调用类型维度:按调用类型隔离(如同步调用、异步调用、定时任务等)
  4. 依赖维度:按外部依赖隔离(如数据库、Redis、第三方接口等)

8.4 实现方式

8.4.1 手动创建多个线程池

// 订单业务线程池
ThreadPoolExecutor orderPool = new ThreadPoolExecutor(...);
// 支付业务线程池
ThreadPoolExecutor payPool = new ThreadPoolExecutor(...);
// 用户业务线程池
ThreadPoolExecutor userPool = new ThreadPoolExecutor(...);

8.4.2 使用框架实现

  • Hystrix:通过@HystrixCommand注解实现线程池隔离
  • Sentinel:通过规则配置实现线程池隔离
  • Resilience4j:轻量级的容错框架,支持线程池隔离

8.4.3 Hystrix线程池隔离示例

@HystrixCommand(
    groupKey = "OrderGroup",
    threadPoolKey = "OrderThreadPool",
    threadPoolProperties = {
   
        @HystrixProperty(name = "coreSize", value = "10"),
        @HystrixProperty(name = "maxQueueSize", value = "20")
    }
)
public void createOrder(Order order) {
   
    // 订单创建逻辑
}

8.5 隔离粒度选择

  • 过粗:隔离效果差,一个业务异常可能影响多个子业务
  • 过细:线程池数量过多,导致系统资源开销大
  • 最佳实践
    • 核心业务单独隔离
    • 非核心业务可以合并隔离
    • 外部依赖必须单独隔离

九、线程池最佳实践与常见坑点

9.1 正确关闭线程池

  • shutdown()
    • 平缓关闭线程池
    • 不接受新任务,但会处理队列中的剩余任务
  • shutdownNow()
    • 强制关闭线程池
    • 不接受新任务,不处理队列中的剩余任务
    • 中断正在执行的任务
  • awaitTermination()
    • 等待线程池关闭完成
    • 设置超时时间,避免无限等待

最佳实践

executor.shutdown();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
   
    executor.shutdownNow();
}

9.2 常见坑点

  1. 任务异常未处理

    • execute()方法抛出的异常会导致线程终止
    • submit()方法抛出的异常会被封装到Future中,不调用get()不会被发现
    • 解决:在任务内部捕获所有异常,或使用UncaughtExceptionHandler
  2. 线程池泄露

    • 线程池未关闭导致应用无法退出
    • 任务中使用了ThreadLocal但未清理
    • 解决:使用try-finally确保线程池关闭,任务结束时清理ThreadLocal
  3. 任务堆积

    • 核心线程数设置过小
    • 队列长度设置过大
    • 任务执行时间过长
    • 解决:合理设置参数,使用动态线程池,监控任务执行时间
  4. 上下文切换频繁

    • 线程数设置过大
    • 任务执行时间过短
    • 解决:减少线程数,合并小任务
  5. 使用Executors创建线程池

    • newFixedThreadPool()newSingleThreadExecutor()使用无界队列,可能导致OOM
    • newCachedThreadPool()最大线程数为Integer.MAX_VALUE,可能导致OOM
    • 解决永远使用ThreadPoolExecutor构造方法创建线程池

9.3 生产环境使用建议

  1. 禁止使用Executors创建线程池,必须手动创建ThreadPoolExecutor
  2. 必须自定义线程工厂,设置有意义的线程名称
  3. 使用有界队列,避免任务堆积导致OOM
  4. 合理设置拒绝策略,并添加告警
  5. 实现线程池监控,及时发现问题
  6. 使用线程池隔离,避免故障扩散
  7. 优先使用动态线程池,提高系统弹性

十、面试核心考点速记

  1. 线程池核心7大参数及作用
  2. 任务提交后的完整执行流程
  3. execute()与submit()的区别(重点是异常处理)
  4. JDK内置4种拒绝策略及适用场景
  5. 核心线程数的计算方法
  6. 为什么不推荐使用Executors创建线程池
  7. 动态线程池的实现原理
  8. 线程池隔离的意义和实现方式
  9. 线程池的正确关闭方式
  10. 线程池常见坑点及解决方案

Java线程池面试八股文精简版(可直接背诵)

标注说明★★★ 高频必考点 | ★★ 中频考点 | 低频考点 | ⚠️ 易错陷阱


一、线程池基础

★★ 核心定义:池化管理线程的技术,基于生产者-消费者模型,解决频繁创建销毁线程的开销问题,提供任务排队、并发控制、监控能力。

★★ 核心优势:降资源消耗、提响应速度、统一管理线程、附加功能(定时/并发控制)。


二、核心7大参数(★★★ 必背)

ThreadPoolExecutor 构造方法7个参数,按顺序背诵:

  1. corePoolSize(核心线程数):长期存活的线程数,默认空闲不销毁;allowCoreThreadTimeOut(true) 可让核心线程超时销毁;懒加载创建。
  2. maximumPoolSize(最大线程数):线程池能创建的最大线程数=核心线程+非核心线程。
  3. keepAliveTime(空闲存活时间):非核心线程空闲后的销毁时间;开启核心线程超时后也作用于核心线程。
  4. unit(时间单位)keepAliveTime 的单位(毫秒/秒/分钟等)。
  5. workQueue(工作队列):存储等待任务的阻塞队列。
    ⚠️ 易错:Executors.newFixedThreadPool() 用无界 LinkedBlockingQueue,会导致OOM。
  6. threadFactory(线程工厂):创建线程的工厂,用于自定义线程名(排查问题必备)、优先级、是否守护线程。
    ⚠️ 最佳实践:永远使用自定义线程工厂,不要用默认的。
  7. handler(拒绝策略):线程池无法处理新任务时的处理逻辑。

三、任务执行原理(★★★ 必背流程)

四步走(按顺序):

  1. 提交任务 → 判断核心线程数是否已满 → 未满:创建核心线程执行
  2. 核心线程已满 → 判断工作队列是否已满 → 未满:加入队列等待
  3. 队列已满 → 判断最大线程数是否已满 → 未满:创建非核心线程执行
  4. 最大线程已满 → 执行拒绝策略

★★ 线程池5种状态
RUNNING(运行)→ SHUTDOWN(不接新任务,处理队列)→ TIDYING(任务全结束)→ TERMINATED(彻底终止)
RUNNING → STOP(不接新任务,中断执行中任务)→ TIDYING → TERMINATED


四、execute() vs submit()(★★★ 必背区别)

对比维度 execute() submit()
入参 仅Runnable Runnable/Callable
返回值 Future对象
异常处理(核心) 未检查异常直接抛出,导致当前线程终止,线程池会新建线程替代 异常封装在Future中,只有调用get()时才抛出ExecutionException,不会终止工作线程
底层 直接执行任务 封装为RunnableFuture,最终调用execute()

⚠️ 易错:submit()的异常不调用get()永远不会被发现,会导致任务"悄无声息"失败。


五、拒绝策略(★★★ 必背)

触发条件:线程池已关闭 OR 最大线程已满且队列已满。

JDK内置4种策略

  1. AbortPolicy(默认):直接抛出RejectedExecutionException
    适用:核心业务,不能容忍任务丢失。
  2. CallerRunsPolicy:由提交任务的线程自己执行。
    特点:不丢任务,自动降速(流量控制)。
    适用:非核心业务,对任务丢失零容忍。
  3. DiscardPolicy:直接丢弃任务,无任何处理。
    适用:完全不重要的任务。
  4. DiscardOldestPolicy:丢弃队列最旧的任务,重新提交当前任务。
    适用:消息处理(允许丢弃旧消息)。

★★ 自定义策略:实现RejectedExecutionHandler接口,逻辑:记录日志+持久化任务+降级处理。


六、参数设计最佳实践(★★★ 必背)

1. 核心线程数计算

  • CPU密集型corePoolSize = CPU核心数 + 1
    原因:几乎无IO等待,线程过多会导致上下文切换开销。
  • IO密集型corePoolSize = CPU核心数 * (1 + 平均等待时间/平均CPU时间)
    简化版:CPU核心数 * 2
    原因:大部分时间在等待IO,多线程可提高CPU利用率。

⚠️ 生产环境:压测调优法优先,先按经验设初始值,再根据CPU利用率、响应时间、吞吐量逐步调整。

2. 其他参数原则

  • maximumPoolSize:一般为corePoolSize的2-4倍;使用SynchronousQueue时需设大一些。
  • 工作队列:永远用有界队列(ArrayBlockingQueue优先),长度建议corePoolSize * 2
  • keepAliveTime:短任务设60秒,长任务设5分钟;核心业务可设0(不允许非核心线程空闲)。

七、动态线程池(★★ 中频考点)

1. 为什么需要

静态参数无法适应动态业务流量:高峰时参数过小导致堆积,低谷时参数过大浪费资源。

2. 可动态调整的参数

corePoolSize、maximumPoolSize、keepAliveTime、拒绝策略(部分实现支持队列容量)。

3. 实现原理

配置中心(Nacos/Apollo)存储参数 → 监听参数变化 → 调用ThreadPoolExecutor的setter方法更新 → 平滑过渡。

4. 主流实现

美团DynamicTp(开源首选)、阿里Sentinel。

5. 核心监控指标(★)

活跃线程数、队列使用率、拒绝任务数、任务平均执行时间。
告警阈值:队列使用率>80%、拒绝任务数>0、活跃线程接近最大线程。


八、线程池隔离(★★ 中频考点)

1. 什么是隔离

将不同业务的任务分配到独立的线程池执行,避免一个业务异常耗尽所有线程资源导致系统雪崩。

2. 隔离维度

  • 业务维度:订单/支付/用户模块分开
  • 依赖维度:数据库/Redis/第三方接口分开(重点)
  • 优先级维度:高/中/低优先级分开

3. 实现方式

  • 手动创建多个线程池(简单直接)
  • 框架实现:Hystrix、Sentinel、Resilience4j

4. 粒度选择

核心业务单独隔离,非核心业务合并隔离,外部依赖必须隔离。


九、最佳实践与常见坑点(★★★ 必背)

1. 绝对禁止

❌ 禁止使用Executors创建线程池:

  • newFixedThreadPool()/newSingleThreadExecutor():无界队列→OOM
  • newCachedThreadPool():最大线程数为Integer.MAX_VALUE→OOM
    ✅ 必须手动new ThreadPoolExecutor()创建。

2. 任务异常处理

  • execute():任务内部必须捕获所有异常,或设置UncaughtExceptionHandler
  • submit():必须调用get()获取异常,或在任务内部捕获

3. 正确关闭线程池

executor.shutdown(); // 平缓关闭,处理剩余任务
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
   
    executor.shutdownNow(); // 超时强制关闭
}

4. 常见坑点

⚠️ 线程池泄露:未关闭线程池→应用无法退出;ThreadLocal未清理→内存泄露。
⚠️ 任务堆积:核心线程过小、队列过大、任务执行时间过长。
⚠️ 上下文切换频繁:线程数设置过大。


十、面试答题技巧

  1. 回答问题先总后分:比如问"线程池执行原理",先说是四步流程,再一步步说。
  2. 结合实际场景:比如问拒绝策略,说清楚每种策略的适用场景,体现实战经验。
  3. 主动延伸:比如问完execute和submit的区别,可以主动说"这也是为什么生产环境推荐用submit并处理Future异常的原因"。
  4. 遇到不会的:诚实说"这个我暂时不太清楚,但我了解相关的XX知识",不要瞎编。
相关文章
|
1月前
|
Arthas 缓存 安全
【Java并发编程】高频实战:死锁排查、线程安全问题定位、线程dump分析(附《思维导图》+《面试高频考点清单》)
本文系统梳理Java并发编程高频实战知识:涵盖死锁排查(Coffman四条件、jstack/Arthas分析)、线程安全定位(竞态/可见性/有序性问题及原子类、Lock、ThreadLocal等方案)与线程Dump深度解析(状态识别、死锁/锁竞争/死循环模式)。
|
4月前
|
SQL 关系型数据库 Java
吃透 Seata 分布式事务:原理拆解 + 生产级落地 + 全场景避坑实战
本文深度解析阿里开源分布式事务框架Seata:剖析TC/TM/RM三大角色与全局事务流程,详解AT(零侵入)、TCC(强控制)、SAGA(长事务)、XA(强一致)四大模式原理、适用场景及核心对比,并通过电商下单实战演示AT模式落地,最后系统梳理生产环境高可用、SQL限制、幂等处理、XID传播等全链路避坑指南。
1163 4
|
3月前
|
消息中间件 监控 Kafka
【消息队列MQ】消息丢失:全链路原因、解决方案、消息可靠性保证
消息队列MQ全链路防丢失体系:覆盖生产→Broker→消费三阶段,直击6大关键节点风险;涵盖确认机制、同步刷盘、主从复制、手动提交Offset、事务消息、死信兜底等核心方案,兼顾可靠性与性能折中。
|
2月前
|
SQL 存储 关系型数据库
【MySQL】《MySQL索引 与 慢SQL优化 面试问答清单》(附《思维导图》)
本文是面向MySQL开发者与DBA的索引与慢SQL优化实战指南,涵盖B+树原理、聚簇/覆盖索引、EXPLAIN深度解读、四大阶段优化(发现→分析→索引→重构)及电商订单/多表联查真实案例,含可打印速查表,助你将慢查询从3秒优化至0.005秒。
【MySQL】《MySQL索引 与 慢SQL优化 面试问答清单》(附《思维导图》)
|
3月前
|
运维 数据库 数据安全/隐私保护
【微服务】微服务 vs 单体架构 区别、服务拆分原则、DDD领域驱动设计
本文构建“架构对比→拆分准则→DDD方法论→落地实践→避坑指南”闭环体系,系统剖析单体与微服务的本质差异、演进路径及反模式;详解微服务拆分八大原则与六大禁忌;深度整合DDD战略设计(限界上下文即服务边界)与战术设计(四层架构+聚合建模),提供从0到1的渐进式落地路径与各阶段最佳实践。
|
SQL 关系型数据库 数据库
学习分布式事务Seata看这一篇就够了,建议收藏
学习分布式事务Seata看这一篇就够了,建议收藏
25746 2
|
2月前
|
存储 监控 NoSQL
【Redis】Redis 高可用:主从复制、哨兵Sentinel、Redis Cluster分片原理、哈希槽、故障转移、数据倾斜优化
本文系统梳理Redis高可用演进路径(单机→主从→哨兵→Cluster),深入解析三大方案原理:主从复制的PSYNC增量同步机制、哨兵的双层下线判定与Raft选举、Cluster的哈希槽分片与Gossip通信。涵盖故障自愈、数据一致、水平扩展等核心目标,及脑裂防控、数据倾斜治理等生产级最佳实践。
|
1月前
|
消息中间件 监控 Java
【Java并发编程】Java虚拟线程与平台线程的区别、虚拟线程调度、适用/不适用场景、在Spring Boot中的集成(2026高频)(附《思维导图》+《面试高频考点清单》)
Java虚拟线程是JDK 21正式推出的轻量级并发方案,由JVM用户态调度,单线程仅占几百字节内存,支持百万级并发。它通过“M:N”调度模型与自动挂载/卸载机制,彻底解决传统平台线程在IO密集型场景下的资源瓶颈与阻塞浪费问题,让同步编程轻松承载高并发。
|
3月前
|
消息中间件 运维 调度
【分布式】分布式核心组件——分布式事务:2PC、TCC、SAGA、本地消息表、事务消息、最大努力通知以及各方案适用场景
本文系统梳理分布式事务核心知识:从CAP/BASE理论基石出发,对比2PC(强一致)、TCC(高并发同步)、SAGA(长事务)、本地消息表、事务消息、最大努力通知六大方案,涵盖原理、优劣、适用场景及选型决策框架,强调“无银弹”,重在业务匹配与工程落地。
|
2月前
|
存储 关系型数据库 MySQL
【MySQL】 索引核心分类:聚簇索引/非聚簇索引、主键索引/二级索引、单列索引/联合索引、覆盖索引/前缀索引
本文系统梳理MySQL索引的四大分类维度:物理存储(聚簇/非聚簇)、功能层级(主键/二级)、字段数量(单列/联合)、优化用途(覆盖/前缀),厘清交叉关系与适用场景,助你科学选型、规避误区、提升查询性能。