线性池java demo

java 复制代码
import java.util.concurrent.*;

public class ThreadPoolDemo {
    
    public static void main(String[] args) {
        // ========== 1. 创建线程池 ==========
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            2,              // corePoolSize: 核心线程数
            4,              // maximumPoolSize: 最大线程数
            60L,            // keepAliveTime: 非核心线程空闲存活时间
            TimeUnit.SECONDS, // 时间单位
            new ArrayBlockingQueue<>(3),  // workQueue: 任务队列,容量3
            new ThreadPoolExecutor.CallerRunsPolicy()  // handler: 拒绝策略
        );
        
        // ========== 2. 提交任务 ==========
        System.out.println("=== 开始提交10个任务 ===\n");
        
        for (int i = 1; i <= 10; i++) {
            int taskId = i;
            executor.submit(() -> {
                // 模拟耗时任务
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.printf("【任务%d】由线程【%s】执行\n", 
                    taskId, Thread.currentThread().getName());
            });
        }
        
        // ========== 3. 关闭线程池 ==========
        executor.shutdown();
        try {
            // 等待所有任务完成
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
        
        System.out.println("\n=== 所有任务执行完成 ===");
    }
}

七个核心参数

有四种拒绝策略

// ① 抛出异常(默认) new ThreadPoolExecutor.AbortPolicy() // ② 丢弃任务,不抛异常 new ThreadPoolExecutor.DiscardPolicy() // ③ 丢弃最老的任务,执行新任务 new ThreadPoolExecutor.DiscardOldestPolicy() // ④ 由调用线程执行(推荐用于重要任务) new ThreadPoolExecutor.CallerRunsPolicy()

线性池的面试考点

【基础类】

  1. 为什么要用线程池?

  2. 线程池的核心参数有哪些?

  3. 线程池的工作流程是什么?

  4. 4种拒绝策略的区别?

【进阶类】

  1. 为什么不建议用Executors创建线程池?

  2. 如何配置线程池参数?

  3. 如何监控线程池?

  4. 如何优雅关闭线程池?

【源码类】

  1. 线程池如何复用线程?

  2. Worker的作用是什么?

  3. 线程池的5种状态?

  4. AQS在线程池中的作用?

【实战类】 13. 生产环境如何配置线程池?

  1. 线程池OOM怎么排查?

  2. 任务执行慢怎么处理?

  3. 如何自定义拒绝策略?

🧵 Java线程池 - 16道面试真题速记版


【基础类】

1️⃣ 为什么要用线程池?

复制代码
✅ 降低资源消耗:复用线程,减少创建/销毁开销
✅ 提高响应速度:任务到达无需等待线程创建
✅ 提高可管理性:统一分配、调优和监控
✅ 控制并发量:防止过多线程导致系统崩溃

2️⃣ 线程池的核心参数有哪些?

复制代码
① corePoolSize    - 核心线程数
② maximumPoolSize - 最大线程数
③ keepAliveTime   - 非核心线程空闲存活时间
④ unit            - 时间单位
⑤ workQueue       - 任务队列
⑥ threadFactory   - 线程工厂
⑦ handler         - 拒绝策略

3️⃣ 线程池的工作流程是什么?

复制代码
1. 提交任务 → 核心线程未满 → 创建核心线程执行
2. 核心线程已满 → 任务放入队列
3. 队列已满 → 创建非核心线程执行
4. 最大线程已满 → 触发拒绝策略

4️⃣ 4种拒绝策略的区别?

策略 行为 场景
AbortPolicy 抛异常(默认) 不允许任务丢失
DiscardPolicy 静默丢弃 任务可丢失(如日志)
DiscardOldestPolicy 丢弃最老任务 新任务更重要
CallerRunsPolicy 调用者线程执行 重要任务,需降级

【进阶类】

5️⃣ 为什么不建议用Executors创建线程池?

复制代码
❌ FixedThreadPool/SingleThreadExecutor:
   队列是LinkedBlockingQueue,容量Integer.MAX_VALUE,可能OOM

❌ CachedThreadPool:
   最大线程数Integer.MAX_VALUE,可能创建过多线程导致OOM

✅ 推荐:手动创建ThreadPoolExecutor,设置有界队列

6️⃣ 如何配置线程池参数?

复制代码
CPU密集型:核心线程数 = CPU核数 + 1
IO密集型:核心线程数 = CPU核数 × 2

队列大小:根据业务峰值和缓冲时间计算
最大线程数:核心线程数 + 缓冲线程
keepAliveTime:60秒左右
拒绝策略:根据业务重要性选择

7️⃣ 如何监控线程池?

复制代码
// 关键指标
executor.getPoolSize()           // 当前线程数
executor.getActiveCount()        // 活跃线程数
executor.getQueue().size()       // 队列大小
executor.getCompletedTaskCount() // 已完成任务数

// 监控方案
1. 定期打印日志
2. 集成Prometheus + Grafana
3. 使用阿里Druid等自带监控的线程池

8️⃣ 如何优雅关闭线程池?

复制代码
// 1. 停止接收新任务
executor.shutdown();

// 2. 等待任务完成(设置超时)
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
    // 3. 超时后强制关闭
    executor.shutdownNow();
}

// 4. 处理未完成任务(持久化等)

【源码类】

9️⃣ 线程池如何复用线程?

复制代码
Worker线程执行完一个任务后,不会直接退出,
而是循环调用getTask()从队列获取新任务,
实现线程复用,减少线程创建/销毁开销

🔟 Worker的作用是什么?

复制代码
Worker是线程池的工作单元,继承AQS:
- 封装实际执行的Thread
- 保存第一个任务firstTask
- 用独占锁保护线程执行状态
- 防止任务执行中被中断

1️⃣1️⃣ 线程池的5种状态?

复制代码
RUNNING    - 接受新任务,处理队列任务
SHUTDOWN   - 不接受新任务,处理队列任务
STOP       - 不接受新任务,不处理队列,中断进行中任务
TIDYING    - 所有任务终止,准备执行terminated()
TERMINATED - 终止完成

1️⃣2️⃣ AQS在线程池中的作用?

复制代码
Worker继承AQS,使用独占锁:
- 保护线程执行状态,防止并发修改
- 判断线程是否正在执行任务
- 支持中断控制和线程状态管理

【实战类】

1️⃣3️⃣ 生产环境如何配置线程池?

复制代码
1. 手动创建ThreadPoolExecutor(不用Executors)
2. 设置有界队列(如ArrayBlockingQueue)
3. 根据任务类型配置线程数(CPU/IO密集型)
4. 设置合理的keepAliveTime
5. 选择合适的拒绝策略
6. 自定义线程工厂(命名、守护线程等)
7. 集成监控和告警

1️⃣4️⃣ 线程池OOM怎么排查?

复制代码
1. 检查队列是否无界(LinkedBlockingQueue)
2. 检查最大线程数是否过大
3. 查看任务是否阻塞或执行过慢
4. 使用jmap查看堆内存
5. 使用jstack查看线程堆栈
6. 检查GC日志和内存泄漏

解决:设置有界队列、限制最大线程数、优化任务

1️⃣5️⃣ 任务执行慢怎么处理?

复制代码
1. 查看活跃线程数和队列大小(监控指标)
2. 使用jstack查看线程堆栈,检查是否死锁
3. 检查GC情况,是否频繁Full GC
4. 检查数据库/网络等外部依赖
5. 适当增加线程数或优化任务逻辑
6. 考虑任务拆分或异步处理

1️⃣6️⃣ 如何自定义拒绝策略?

复制代码
// 实现RejectedExecutionHandler接口
class MyRejectHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        // 1. 记录日志
        log.warn("任务被拒绝: {}", r);
        
        // 2. 持久化到数据库/消息队列
        // saveToMQ(r);
        
        // 3. 发送告警
        // sendAlert();
    }
}

// 使用
new ThreadPoolExecutor(..., new MyRejectHandler());

📋 速记口诀

复制代码
线程池,七参数,核心最大队列满
拒绝策略有四种,生产不用Executors
CPU型,N+1,IO型,N乘2
监控关闭要做好,源码Worker要理解

相关推荐
追随者永远是胜利者1 小时前
(LeetCode-Hot100)5. 最长回文子串
java·算法·leetcode·职场和发展·go
强子感冒了1 小时前
JavaScript 零基础入门笔记:核心概念与语法详解
开发语言·javascript·笔记
小灵不想卷1 小时前
LangChain4j 多模态
java·langchain4j
wuqingshun3141591 小时前
String、StringBuffer、StringBuilder的应用场景
java·开发语言·jvm
桂花很香,旭很美1 小时前
[7天实战入门Go语言后端] Day 5:中间件与业务分层——日志、鉴权与请求超时
开发语言·中间件·golang
日月云棠2 小时前
JDK 17 特性详解
java
追随者永远是胜利者2 小时前
(LeetCode-Hot100)19. 删除链表的倒数第 N 个结点
java·算法·leetcode·链表·go
树码小子2 小时前
Mybatis(14)Mybatis-Plus入门 & 简单使用
java·mybatis-plus
人道领域2 小时前
Maven配置加载:动态替换的艺术
java·数据库·后端