hello啊,各位观众姥爷们!!!本baby今天又来报道了!哈哈哈哈哈嗝🐶
面试资料大全|各种技术资料-2000G
一、线程池核心原理
1. Java线程池体系结构
Executor (接口)
↑
ExecutorService (接口)
↑
AbstractExecutorService (抽象类)
↑
ThreadPoolExecutor (核心实现类)
2. ThreadPoolExecutor关键参数
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 工作队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)
3. 线程池工作流程
二、自定义线程池实践
1. 典型配置方案
// IO密集型任务配置
ThreadPoolExecutor ioIntensivePool = new ThreadPoolExecutor(
2 * Runtime.getRuntime().availableProcessors(),
4 * Runtime.getRuntime().availableProcessors(),
60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new CustomThreadFactory("io-pool"),
new CustomRejectionPolicy()
);
// CPU密集型任务配置
ThreadPoolExecutor cpuIntensivePool = new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors(),
0, TimeUnit.SECONDS,
new SynchronousQueue<>(),
new CustomThreadFactory("cpu-pool")
);
2. 自定义线程工厂
public class CustomThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger threadNumber = new AtomicInteger(1);
public CustomThreadFactory(String poolName) {
this.namePrefix = poolName + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
t.setDaemon(false); // 非守护线程
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
三、拒绝策略深度解析
1. JDK内置策略对比
策略类 | 行为 | 适用场景 |
---|---|---|
AbortPolicy | 直接抛出RejectedExecutionException | 需要严格保证任务不丢失的场景 |
CallerRunsPolicy | 由提交任务的线程直接执行 | 适合能接受降级的业务场景 |
DiscardPolicy | 静默丢弃任务 | 监控不敏感的非关键任务 |
DiscardOldestPolicy | 丢弃队列中最老的任务并重试 | 允许丢弃旧任务的实时性要求不高的场景 |
2. 自定义拒绝策略实现
public class CustomRejectionPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 1. 记录日志和监控指标
log.warn("Task rejected: {}", r.toString());
monitor.recordRejection();
// 2. 尝试将任务持久化到数据库
if (!saveToDb(r)) {
// 3. 备用处理方案
if (!executor.isShutdown()) {
r.run(); // 由当前线程直接执行
}
}
}
}
3. 混合策略实现
public class HybridRejectionHandler implements RejectedExecutionHandler {
private final RejectedExecutionHandler[] handlers;
public HybridRejectionHandler(RejectedExecutionHandler... handlers) {
this.handlers = handlers;
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
for (RejectedExecutionHandler handler : handlers) {
try {
handler.rejectedExecution(r, executor);
return;
} catch (Exception e) {
log.error("Rejection handler failed", e);
}
}
throw new RejectedExecutionException("All handlers failed");
}
}
四、应用场景分析
1. 线程池选型场景
场景类型 | 推荐配置 | 理由 |
---|---|---|
Web请求处理 | core=200, max=400, queue=500, 拒绝策略=CallerRunsPolicy | 平衡吞吐量和响应时间,避免雪崩 |
批量数据处理 | core=CPU数, max=CPU数, queue=10000, 拒绝策略=AbortPolicy | 保证数据处理顺序,队列缓冲大批量任务 |
实时交易系统 | core=CPU数2, max=CPU数4, queue=0(SynchronousQueue), 策略=自定义持久化 | 低延迟优先,拒绝时确保交易不丢失 |
定时任务调度 | 使用ScheduledThreadPoolExecutor | 专为定时任务优化 |
2. 拒绝策略选型场景
业务特征 | 推荐策略 | 原因分析 |
---|---|---|
支付订单处理 | 自定义持久化策略 | 资金交易必须保证不丢失 |
用户行为日志收集 | DiscardOldestPolicy | 可以容忍部分日志丢失,保证最新数据优先 |
API网关限流 | AbortPolicy | 快速失败让调用方知道系统繁忙 |
后台报表生成 | CallerRunsPolicy | 降级为同步执行保证任务完成 |
五、高级实践技巧
1. 线程池监控
// 定时采集指标
ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor();
monitor.scheduleAtFixedRate(() -> {
log.info("Pool status: {}/{} active, queue size: {}, completed: {}",
pool.getActiveCount(),
pool.getPoolSize(),
pool.getQueue().size(),
pool.getCompletedTaskCount());
}, 1, 1, TimeUnit.SECONDS);
2. 动态调参
// 根据负载动态调整
if (queueSize > threshold) {
executor.setCorePoolSize(newCoreSize);
executor.setMaximumPoolSize(newMaxSize);
}
3. 上下文传递
// 使用ThreadLocal + 装饰器模式
public class ContextAwareRunnable implements Runnable {
private final Runnable task;
private final Map<String, Object> context;
public ContextAwareRunnable(Runnable task) {
this.task = task;
this.context = ThreadLocalContext.getCurrentContext();
}
@Override
public void run() {
ThreadLocalContext.setContext(context);
try {
task.run();
} finally {
ThreadLocalContext.clear();
}
}
}
六、常见问题解决方案
1. 线程泄漏问题
- 症状:线程数持续增长不释放
- 排查:
// 获取所有工作线程 ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); long[] threadIds = threadBean.getAllThreadIds(); for (long id : threadIds) { ThreadInfo info = threadBean.getThreadInfo(id); if (info.getThreadName().startsWith("custom-pool")) { System.out.println(info); // 打印堆栈 } }
- 解决:确保任务不会无限阻塞
2. 任务堆积问题
- 优化方案:
- 使用有界队列 + 合理的拒绝策略
- 引入背压机制(如RxJava的Flowable)
3. 死锁问题
- 预防措施:
- 避免跨任务锁竞争
- 使用
ThreadPoolExecutor#getActiveCount()
监控
七、性能优化建议
-
队列选择:
ArrayBlockingQueue
:固定大小,内存友好LinkedBlockingQueue
:无界/有界灵活,吞吐量高SynchronousQueue
:直接传递,零队列
-
线程数公式:
- CPU密集型:
N_cpu + 1
- IO密集型:
N_cpu * (1 + WT/ST)
- WT:等待时间
- ST:计算时间
- CPU密集型:
-
预热优化:
executor.prestartAllCoreThreads(); // 启动所有核心线程