Java 自带的线程池(Executors 工具类)
Java 通过 Executors 工具类提供了5 种常用的自带线程池 ,底层都是基于 ThreadPoolExecutor 实现的,简化了线程池的创建。
注意:阿里开发手册不建议直接使用 Executors 创建线程池 (部分实现存在 OOM 风险),但作为基础知识点必须掌握,生产环境推荐手动定义
ThreadPoolExecutor。
一、5 种内置线程池详解
- **
newFixedThreadPool**固定大小线程池
-
核心特点:核心线程数 = 最大线程数
-
使用队列 LinkedBlockingQueue 无界队列
-
适用场景 :控制最大并发数,负载稳定的任务
-
特性:线程数量固定,空闲线程不会被回收,队列无限制
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPoolDemo {
public static void main(String[] args) {
// 创建固定 3 个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交 10 个任务
for (int i = 1; i <= 10; i++) {
int taskNum = i;
executor.execute(() -> {
System.out.println("任务 " + taskNum + " 被线程 " + Thread.currentThread().getName() + " 执行");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// 关闭线程池
executor.shutdown();
}
}
newCachedThreadPool缓存线程池
-
核心特点 :无核心线程,最大线程数**
Integer.MAX_VALUE**,自动回收空闲线程 -
队列类型 SynchronousQueue(不存任务,来一个任务必须立刻开线程 最大线程21 亿)
-
适用场景 :大量短生命周期、轻量级的异步任务
-
特性 :来任务就创建线程,空闲 60 秒自动销毁,任务密集时会无限创建线程(OOM 风险)
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 1; i <= 10; i++) {
int taskNum = i;
executor.execute(() -> {
System.out.println("任务 " + taskNum + " 被线程 " + Thread.currentThread().getName() + " 执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown();
}
}
- **
newSingleThreadExecutor**单线程线程池
-
核心特点:只有 1 个核心线程
-
使用队列 LinkedBlockingQueue 无界队列
-
适用场景 :任务串行执行,保证顺序
-
特性:所有任务按提交顺序执行,线程异常会自动重建
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExecutorDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 1; i <= 5; i++) {
int taskNum = i;
executor.execute(() -> {
System.out.println("任务 " + taskNum + " 被线程 " + Thread.currentThread().getName() + " 执行");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown();
}
}
4.newScheduledThreadPool 定时 / 周期线程池
-
核心特点:支持延迟执行、周期性执行任务
-
使用队列 DelayedWorkQueue 延迟队列
-
适用场景 :定时任务、周期任务(如定时报表、定时清理)
-
特性 :基于
ScheduledExecutorService,核心线程固定,非核心线程无限->OOM
java
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolDemo {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
// 1. 延迟 2 秒执行一次
executor.schedule(() -> {
System.out.println("延迟任务执行:" + System.currentTimeMillis());
}, 2, TimeUnit.SECONDS);
// 2. 初始延迟 1 秒,之后每 3 秒执行一次(固定频率)
executor.scheduleAtFixedRate(() -> {
System.out.println("周期任务执行:" + System.currentTimeMillis());
}, 1, 3, TimeUnit.SECONDS);
}
}
newWorkStealingPool抢占式线程池(JDK8+)
-
核心特点 :基于ForkJoinPool,多任务队列,工作窃取算法
-
使用队列
WorkStealingQueue(工作窃取队列) ,本质是ForkJoinPool的内部队列机制 -
队列特点:
-
双端队列(Deque):每个线程都有自己的任务队列
-
窃取机制:当自己的队列任务干完了,会去 "偷" 别的线程队列里的任务(通常是偷尾巴,减少竞争)
-
适用场景 :CPU 密集型任务,任务之间相互独立
-
特性:默认线程数 = CPU 核心数,并行效率高,异步处理能力强
-
缺点: 不适合 IO 密集型任务(网络、数据库、文件)一个 IO 阻塞会拖慢所有线程,不能保证任务执行顺序,不能手动设置队列大小
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class WorkStealingPoolDemo {
public static void main(String[] args) {
// 无参:默认线程数 = CPU 核心数
ExecutorService executor = Executors.newWorkStealingPool();
for (int i = 1; i <= 10; i++) {
int taskNum = i;
executor.execute(() -> {
System.out.println("任务 " + taskNum + " 被线程 " + Thread.currentThread().getName() + " 执行");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// workStealingPool 是守护线程,需要阻塞等待
try {
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
二 生产的线程池封装
1常量配置(建议放 application.yml 里)
java
public class ThreadPoolConstant {
// CPU核心数
public static final int CPU_CORE = Runtime.getRuntime().availableProcessors();
// IO密集型:核心线程 = CPU * 2
public static final int CORE_POOL_SIZE = CPU_CORE * 2;
// 最大线程
public static final int MAX_POOL_SIZE = CPU_CORE * 4;
// 空闲线程存活时间
public static final long KEEP_ALIVE_SECONDS = 60L;
// 队列容量(必须有界!)
public static final int QUEUE_CAPACITY = 2048;
// 线程名前缀(非常重要)
public static final String THREAD_NAME_PREFIX = "biz-async-task-";
}
自定义线程工厂(带命名、优先级、守护线程)
java
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
public class BizThreadFactory implements ThreadFactory {
private final AtomicInteger threadSeq = new AtomicInteger(1);
private final String threadNamePrefix;
public BizThreadFactory(String threadNamePrefix) {
this.threadNamePrefix = threadNamePrefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
// 设置线程名
thread.setName(threadNamePrefix + threadSeq.getAndIncrement());
// 非守护线程,确保任务执行完
thread.setDaemon(false);
// 正常优先级
thread.setPriority(Thread.NORM_PRIORITY);
// 异常捕获(防止线程池里任务异常导致线程消失)
thread.setUncaughtExceptionHandler((t, e) -> {
log.error("线程 [{}] 执行任务异常", t.getName(), e);
});
log.info("创建业务线程: {}", thread.getName());
return thread;
}
}
自定义拒绝策略(记录日志 + 降级处理)
java
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
public class BizRejectedPolicy implements ThreadPool.RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 打印关键监控信息
log.error(
"线程池拒绝任务!" +
" 活跃线程数:{}" +
" 队列大小:{}" +
" 已完成任务数:{}",
executor.getActiveCount(),
executor.getQueue().size(),
executor.getCompletedTaskCount()
);
// 核心业务拒绝策略:让调用者同步执行(不丢任务)
if (!executor.isShutdown()) {
log.warn("触发CallerRuns降级策略,由主线程同步执行任务");
r.run();
}
}
}
线程池单例封装
java
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.*;
@Component
@Slf4j
public class BizAsyncThreadPool {
@Getter
private ThreadPoolExecutor executor;
@PostConstruct
public void init() {
log.info("===== 初始化业务异步线程池开始 =====");
// 1. 队列:有界队列,防止OOM
BlockingQueue<Runnable> workQueue =
new ArrayBlockingQueue<>(ThreadPoolConstant.QUEUE_CAPACITY);
// 2. 线程工厂
ThreadFactory threadFactory =
new BizThreadFactory(ThreadPoolConstant.THREAD_NAME_PREFIX);
// 3. 拒绝策略
RejectedExecutionHandler rejectedHandler = new BizRejectedPolicy();
// 4. 创建线程池
executor = new ThreadPoolExecutor(
ThreadPoolConstant.CORE_POOL_SIZE,
ThreadPoolConstant.MAX_POOL_SIZE,
ThreadPoolConstant.KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS,
workQueue,
threadFactory,
rejectedHandler
);
// 允许核心线程超时回收(空闲时释放资源)
executor.allowCoreThreadTimeOut(true);
log.info("===== 初始化业务异步线程池完成 =====");
log.info("核心线程数:{},最大线程数:{},队列容量:{}",
executor.getCorePoolSize(),
executor.getMaximumPoolSize(),
workQueue.size()
);
}
// ====================== 提交任务 ======================
/**
* 无返回值任务
*/
public void execute(Runnable task) {
executor.execute(task);
}
/**
* 带返回值任务
*/
public <T> Future<T> submit(Callable<T> task) {
return executor.submit(task);
}
// ====================== 优雅停机 ======================
@PreDestroy
public void shutdown() {
log.info("===== 开始关闭业务异步线程池 =====");
// 拒绝新任务
executor.shutdown();
try {
// 等待60秒,让现有任务执行完
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
log.warn("线程池关闭超时,强制关闭");
executor.shutdownNow();
}
} catch (InterruptedException e) {
log.error("线程池关闭被中断,强制关闭");
executor.shutdownNow();
Thread.currentThread().interrupt();
}
log.info("===== 业务异步线程池已关闭 =====");
}
}
业务使用示例Service 中
java
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@Slf4j
public class TestController {
private final BizAsyncThreadPool bizAsyncThreadPool;
@GetMapping("/test/async")
public String testAsync() {
log.info("主线程开始处理请求");
// 提交异步任务:发送短信
bizAsyncThreadPool.execute(() -> {
try {
// 模拟调用第三方短信接口
log.info("【异步任务】开始发送短信...");
Thread.sleep(1000);
log.info("【异步任务】短信发送成功");
} catch (InterruptedException e) {
log.error("发送短信异常", e);
Thread.currentThread().interrupt();//sleep()wait()join()遇到会抛出InterruptedException 异常
}
});
// 提交异步任务:记录日志
bizAsyncThreadPool.execute(() -> {
try {
log.info("【异步任务】记录操作日志");
Thread.sleep(500);
log.info("【异步任务】日志落库成功");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
log.info("主线程立即返回");
return "success";
}
}
生产级定时任务线程池
java
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class ScheduledTaskPool {
@Getter
private ScheduledThreadPoolExecutor executor;
@PostConstruct
public void init() {
// 核心线程固定2~4个足够
executor = new ScheduledThreadPoolExecutor(2,
new BizThreadFactory("biz-scheduled-task-")
);
// 关键!限制最大线程,防止无限创建
executor.setMaximumPoolSize(4);
executor.setRejectedExecutionHandler(new BizRejectedPolicy());
executor.setKeepAliveTime(60L, TimeUnit.SECONDS);
executor.allowCoreThreadTimeOut(true);
log.info("定时任务线程池初始化完成");
}
/**
* 固定频率执行
*/
public void scheduleAtFixedRate(Runnable task, long initialDelay, long period)//任务 初始延迟 周期
{
executor.scheduleAtFixedRate(task, initialDelay, period, TimeUnit.SECONDS);
}
/**
* 固定间隔执行
*/
public void scheduleWithFixedDelay(Runnable task, long initialDelay, long delay)//任务 初始延迟 间隔
{
executor.scheduleWithFixedDelay(task, initialDelay, delay, TimeUnit.SECONDS);
}
@PreDestroy
public void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
三 线程池基础知识
ThreadPoolExecutor 7 大参数 + 队列 + 拒绝策略
线程池构造方法
真正的线程池只有这一个:
java
new ThreadPoolExecutor(
int corePoolSize, // 1. 核心线程数
int maximumPoolSize, // 2. 最大线程数
long keepAliveTime, // 3. 空闲线程存活时间
TimeUnit unit, // 4. 时间单位
BlockingQueue<Runnable> workQueue, // 5. 任务队列
ThreadFactory threadFactory, // 6. 线程工厂
RejectedExecutionHandler handler // 7. 拒绝策略
);
7 大参数系统讲解
- corePoolSize 核心线程数
-
线程池中长期保留的常驻线程
-
即使空闲,默认也不会被销毁
-
IO 密集型:设置为 CPU 核心数 × 2 (IO等待为主 实际不消耗)
-
CPU 密集型:设置为 CPU 核心数 + 1(计算为主 减少线程切换上下文消耗)
- maximumPoolSize 最大线程数
-
线程池最多能创建多少线程
-
当队列满了,才会创建新线程,直到达到这个数
-
不能无限大,否则 OOM
- keepAliveTime 空闲线程存活时间
-
超过核心线程数的线程,空闲多久会被回收
-
一般设 60 秒
- unit 时间单位
-
秒、毫秒等
-
配合 keepAliveTime 使用
- workQueue 任务队列(重点)
任务进来,先放队列,队列满了才开新线程。
常用 3 种:
-
ArrayBlockingQueue
-
有界队列
-
生产环境必须用这个
-
可以设置容量,防止 OOM
-
-
LinkedBlockingQueue
-
无界队列(默认容量 Integer.MAX_VALUE)
-
Executors 固定线程池用这个
-
任务无限堆积 → OOM
-
-
SynchronousQueue
-
不存储任务,来一个任务必须立刻开线程
-
缓存线程池用这个
-
高并发会疯狂创建线程 → OOM
-
-
threadFactory 线程工厂
-
用来创建线程
-
生产必须自定义:
-
设置线程名(排查问题必备)
-
设置是否守护线程(后台辅助线程,只要所有用户线程都结束,JVM 直接杀死所有守护线程)
-
设置异常捕获
-
- handler 拒绝策略(重点)
当:线程数达到 maximumPoolSize并且队列已满新任务进来就会触发拒绝策略。
三、4 种拒绝策略(系统整理)
- AbortPolicy(默认)
-
直接抛出异常 RejectedExecutionException
-
阻止任务提交
-
生产不推荐,会直接报错
- CallerRunsPolicy(生产最推荐)
-
让提交任务的主线程自己执行这个任务
-
不会丢任务
-
不会抛异常
-
压力大时能自动限流、保护系统
- DiscardPolicy
-
直接丢弃任务,不抛异常
-
业务不能丢任务时绝对不能用
- DiscardOldestPolicy
-
丢弃队列里最老的任务
-
再尝试提交当前任务
-
可能导致关键任务丢失,慎用