Java线程池原理、使用规范、常用并发异步工具类

约 3470 字

Java线程池原理、使用规范、常用并发异步工具类

本文全覆盖:线程池核心原理、七大参数详解、工作机制、拒绝策略、内置线程池弊端、生产自定义线程池、线程池复用原理、四大并发异步工具类,解决线程池95%面试和线上问题,逻辑闭环、可直接背诵。

一、线程池核心原理(为什么用线程池)

1. 原生new Thread的弊端

  • 频繁创建、销毁线程,开销极大(OS内核线程创建成本高)
  • 无限制创建线程,导致线程泛滥、上下文切换爆炸、OOM
  • 缺乏统一管理、任务排队机制

2. 线程池核心作用

线程复用、控制并发、统一管理、降低开销

  • 复用线程:线程创建一次,循环处理任务,避免频繁销毁创建
  • 限流保护:控制最大并发线程数,保护服务器CPU、内存资源
  • 任务队列缓冲:削峰填谷,应对突发流量
  • 可监控、可拒绝、可优雅关闭

二、线程池七大核心参数(面试必考)

ThreadPoolExecutor 完整构造器7个参数,是线程池底层核心

  1. corePoolSize 核心线程数:常驻线程,不会被超时回收
  2. maximumPoolSize 最大线程数:线程池允许的最大并发线程数量
  3. keepAliveTime 空闲超时时间:非核心线程空闲超时后被回收
  4. unit 时间单位:配合超时时间使用
  5. workQueue 任务阻塞队列:存放等待执行的任务
  6. threadFactory 线程工厂:创建线程,自定义线程名、优先级、守护线程
  7. handler 拒绝策略:任务满负荷后,新任务的处理策略

三、线程池完整工作流程(满分背诵)

任务提交执行顺序:核心线程 → 队列 → 最大线程 → 拒绝策略

  1. 提交任务,判断当前线程数 < 核心线程数:新建核心线程执行任务
  2. 核心线程已满,判断队列是否未满:任务放入阻塞队列排队
  3. 队列已满,判断当前线程数 < 最大线程数:新建非核心线程执行任务
  4. 达到最大线程数 + 队列已满:触发拒绝策略
  5. 非核心线程空闲超过 keepAliveTime:自动回收,节省资源

四、四大拒绝策略(JDK内置)

  1. AbortPolicy(默认):直接抛出异常,中断任务,生产不推荐
  2. CallerRunsPolicy:谁提交谁执行(主线程自己跑),不抛异常、不丢任务,生产最稳
  3. DiscardPolicy:直接丢弃当前新任务,无日志、无异常,风险高
  4. DiscardOldestPolicy:丢弃队列最老任务,执行新任务,适合实时性任务

五、四种内置线程池 & 致命弊端(阿里规范)

生产禁止使用 Executors 内置线程池!全部存在隐患

1. FixedThreadPool(固定线程池)

  • 核心线程=最大线程,无空闲回收
  • 弊端:队列是无界队列 LinkedBlockingQueue,任务无限堆积 → OOM

2. CachedThreadPool(缓存线程池)

  • 核心线程0,最大线程Integer.MAX_VALUE
  • 弊端:线程无限创建 → 线程泛滥、CPU打满、OOM

3. SingleThreadExecutor(单线程池)

  • 单个线程串行执行
  • 弊端:无界队列,任务堆积OOM

4. ScheduledThreadPool(定时线程池)

  • 支持定时、周期任务
  • 弊端:最大线程数无限,高并发线程爆炸

六、生产环境正确使用方式(必背)

手动自定义 ThreadPoolExecutor + 有界队列 + 自定义线程名 + 合理拒绝策略

  • 队列必须使用 有界队列(如ArrayBlockingQueue),限制任务数量,防止OOM
  • 自定义线程工厂,设置线程名称,方便线上排查堆栈
  • 拒绝策略优先使用 CallerRunsPolicy,保证不丢任务、不抛异常雪崩
  • 根据业务IO密集/CPU密集配置参数

参数配置经验值

  • CPU密集型:核心线程数 = CPU核心数 + 1(减少上下文切换)
  • IO密集型:核心线程数 = CPU核心数 * 2 或 20–50(等待IO,可多开线程)

七、线程池核心拓展知识点

1. 线程池线程复用原理

线程启动后不会退出,底层通过 while死循环 + 队列take() 不断阻塞获取新任务,实现线程永久复用,只有线程超时/关闭才会退出。

2. 核心线程会不会回收?

默认不会。可通过 allowCoreThreadTimeOut(true) 开启核心线程超时回收,极致节省资源。

3. 线程池关闭方式

  • shutdown():平缓关闭,停止接收新任务,执行完队列剩余任务
  • shutdownNow():强制关闭,尝试中断正在执行任务,清空队列

八、Java 四大常用并发/异步工具类(面试高频)

1. CompletableFuture(JDK8 异步编程神器)

解决问题:替代 Future,解决回调地狱、无法链式编程、获取结果阻塞问题,实现全异步链式编程。

核心能力

  • 异步执行任务、非阻塞获取结果
  • 链式调用:thenApply、thenAccept、thenRun
  • 多任务组合:allOf(全部完成)、anyOf(任意一个完成)
  • 异常优雅捕获

适用场景

多接口并行查询、复杂异步编排、微服务多接口聚合、批量异步处理

2. CountDownLatch(倒计时计数器)

核心作用:一个线程等待多个线程执行完毕,一次性使用、不可重置。

原理

  • 构造传入总次数count
  • 子线程执行完调用 countDown() 计数器-1
  • 主线程 await() 阻塞,直到count=0唤醒

场景

多线程批量任务、并行处理后汇总结果

3. CyclicBarrier(循环栅栏)

核心作用:多个线程互相等待,全部到位再统一执行,可循环复用。

区别CountDownLatch

  • CountDownLatch:主线等子线程,一次性
  • CyclicBarrier:子线程互相等,可循环复用

场景

多阶段分批任务、多人组队同步执行、循环批量处理

4. Semaphore(信号量)

核心作用:控制并发限流,限制同时执行的线程数量

原理

  • permits 许可数 = 最大并发数
  • acquire() 获取许可,没有则阻塞
  • release() 释放许可

场景

接口限流、数据库连接限流、第三方接口调用限流、秒杀并发控制


九、四大并发工具类终极对比(背诵版)

  • CountDownLatch:倒计时,主线等子线程,一次性
  • CyclicBarrier:栅栏等待,线程互相等,可循环
  • Semaphore:并发限流,控制同时运行线程数
  • CompletableFuture:异步任务编排、多任务组合、链式异步编程

十、面试终极总结(直接背诵)

线程池通过线程复用降低创建销毁开销,通过七大参数控制并发与排队;工作流程遵循核心线程→队列→最大线程→拒绝策略。禁止使用JDK内置线程池,必须自定义有界队列线程池防止OOM。并发工具中,CountDownLatch用于批量等待、CyclicBarrier用于循环同步、Semaphore用于限流、CompletableFuture用于异步任务编排。